Follow-up to #5, this time focusing on things I spotted in our integration.
Wagtail functionality
There is Wagtail-specific functionality here:
|
from wagtail.contrib.forms.forms import FormBuilder |
Do we really want Wagtail to be a dependency of tbxforms
? It feels a bit odd to me, and makes the template pack somewhat harder to reuse and maintain since anyone using this will have to make sure their dependencies are compatible with those of Wagtail. Could we instead conditionally have this code (and the import) only run if wagtail.contrib.forms
is in INSTALLED_APPS?
XSS injection vectors
The templates make a lot of use of |safe
, which makes me feel wary at the very least, and will be a source of XSS vulnerabilities when forms are defined via user input (the Wagtail form builder in particular).
Testing the current implementation of BaseWagtailFormBuilder and the templates,
- This makes it possible do an XSS injection via the fields’ label
- The buttons label also allows XSS injection (
input.value|safe
in button.html)
- The injection via help_text is prevented by WAGTAILFORMS_HELP_TEXT_ALLOW_HTML – so we’re good, but it’d be nice if similarly usage of
|safe
for help text was configurable within the template pack (rather than trusting it’s done upstream).
- For sites that make it possible to do fieldsets and legends (with implementations like wagtailstreamforms), I’m pretty sure there would be more injection opportunities.
So – I’d suggest:
- Removing the
|safe
for anything that doesn’t strictly need it
- For things that do need it, checking whether there might be more bespoke sanitisation we could introduce
- Documenting which things we’d expect implementers of the template pack to sanitise themselves
IE11 compatibility
The conditional fields don’t work for me in IE11. There is ES6+ syntax used in the published code, which creates a syntax error in IE11:
class TbxForms {
static selector() {
return "form.tbxforms";
}
It looks like Vite (esbuild) unfortunately doesn’t support compiling down to ES5 (what we’d need for IE11 compatibility), the build.target
only goes down to es2015 (ES6).
The simplest way to fix this would be to rewrite the JS code to not use the class syntax (which isn’t that good to start with, and doesn’t do much for this project – just make a function initTbxForms(node) {}
, and a separate clearInput
function. I think this should work as long as esbuild doesn’t do any minification. We’ll need to make sure no other part of the code uses ES6+ syntax either (template literals, arrow functions, const
, etc.).
Alternatively – we could switch over to Babel for the production build. For a single file like this, the setup is very straightforward with Rollup. See for example https://github.com/thibaudcolas/draftjs-filters/blob/main/rollup.config.js.
Note due to this I haven’t been able to test the things I was worried about initially (dispatchEvent
).
Conditional fields
I could spot a number of issues with this:
Reliance on JS
- The way fields are implemented, they will be visible if JS fails to execute on the page. It’s unclear to me whether this is intended or not.
- Due to this approach, when the page loads the conditional parts of the form are visible for a moment. I think it would be better if the fields were hidden on page load.
Clear hidden fields on submit
This doesn’t seem to be working. Looking at the code, I think this is because the [hidden=true]
selector won’t work, should be [hidden]
.
In addition,
- Clearing the
value
on submit
and reset
inputs won’t be very desirable. It seems unlikely for us to use either, but I’d still prefer we don’t remove their label
- I haven’t been able to test it but I don’t think clearing a
radio
or checkbox
works like the code suggests - you’d need to find which input is checked, then .checked = false
.
- For
select
– the node.type
I get select-one
, and I think it would be better to set selectedIndex to 0.
ARIA
- The fields’
aria-describedby
has the help text first, error messages second, while in the template we show the error messages first. I think both should match. I like the idea of having errors first, so the beginning of the field’s description is "Error:". Means we don’t need to additionally have aria-invalid="true"
.
Styles
- We should use the American spelling
color
for the API / variables, so it matches CSS. We tend to avoid british spellings for things that have corresponding CSS keywords or property names.