A label that names nothing
What it costs you
This <label> has no htmlFor and no id, and the field beside it carries no name of its own, so the two are never connected. Clicking the text does not focus the field, a screen reader announces the input as unlabelled, voice control has no name to address it by, and browser autofill loses the hint it uses to fill the form.
The defect, and the fix
Both samples are scanned as app/components/SignupForm.tsx.
Our test suite runs both through the scanner on every build: the first must be reported, the second must not.
export function SignupForm() {
return (
<form>
<label>Email address</label>
<input type="email" name="email" />
</form>
);
}export function SignupForm() {
return (
<form>
<label htmlFor="email">Email address</label>
<input id="email" type="email" name="email" />
</form>
);
}What changed: The label points at the input, so a screen reader reads the field's name and clicking the text focuses the field.
How to fix it
Give the field an id and point the label at it — <label htmlFor="email">Email</label><input id="email" />. Wrapping the input inside the label works too and needs no ids.
Why this rule doesn't cry wolf
Each clause below exists because it was attacked: someone was asked to find correct code that the rule would flag, and the clause is what stopped it. This is published because a check you cannot audit is a check you have to take on faith.
JSX files only, outside tests/docs/examples; the label must be non-self-closing with no htmlFor/for, no id, no aria-* and no spread; its children must be literal text with no {expression}, no nested control and no capitalised component; a NATIVE input/select/textarea must follow within ~200 characters with no other <label> intervening; that field must not carry aria-label/aria-labelledby or type="hidden"; and the whole rule stands down if the repo already runs eslint-plugin-jsx-a11y. Each clause removes a class of correct code: for= in non-JSX templates, aria-labelledby pairs, prop-forwarding wrappers, slot children, implicit wrapping, and design-system fields that thread their own id.
This is not a security finding
QA008 is reported in its own section, separately from security findings. It does not change your security grade, and it does not fail your build unless you pass --fail-on-quality. The security catalogue lives at /rules.
Other Accessibility checks
Check your own code
npx xploitscan scan .Runs on every plan, including free. All 12 quality checks.