feat(a11y): add SR-only labels to FormField (Closes #381)#462
Open
Topmatrixmor2014 wants to merge 1 commit into
Open
feat(a11y): add SR-only labels to FormField (Closes #381)#462Topmatrixmor2014 wants to merge 1 commit into
Topmatrixmor2014 wants to merge 1 commit into
Conversation
Expose a screen-reader-only label mode so placeholder-driven inputs can still meet WCAG 2.1 AA programmatic naming requirements via htmlFor/id. Closes CredenceOrg#381 Co-authored-by: Cursor <cursoragent@cursor.com>
|
@Topmatrixmor2014 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds
srOnlyLabelsupport to the sharedFormFieldwrapper so form controls that rely on a visible placeholder (or other non-label visual affordance) can still expose a proper programmatic accessible name for assistive technology.Closes #381
Problem
WCAG 2.1 AA requires every form control to have an accessible name. A visible placeholder is not a label — it disappears once the user types, is often low-contrast, and is not consistently announced by screen readers as the field name.
FormFieldalready rendered a visible<label htmlFor={id}>, but there was no supported pattern for placeholder-only layouts where designers omit the visible label while accessibility still requires a hidden<label>linked viafor/id.Solution
Added an optional
srOnlyLabel?: booleanprop (defaultfalse) toFormField:srOnlyLabel={true}, the existing<label htmlFor={id}>receives the project-standardsr-onlyutility class (defined insrc/index.css, already used byRouteAnnouncer,ConfirmDialog,TierLadder, etc.).<label>element — not a<span>— preserving nativehtmlFor/idassociation.srOnlyLabelis omitted (backwards compatible).aria-describedby,aria-invalid,role="alert") is unchanged.Example usage
Screen readers announce "Search attestations" as the field name; sighted users see only the placeholder.
Files changed
src/components/forms/FormField.tsxsrOnlyLabelprop; applysr-onlyclass conditionallysrc/components/forms/FormField.test.tsxsrc/components/forms/FormField.stories.tsxSrOnlyLabelStorybook storydocs/components.mddocs/FORMS_AND_INPUTS.mdAccessibility verification
Axe (affected route:
/attestations)Manual review against WCAG rules enforced by axe:
labelAttestationFormfields already use visibleFormFieldlabels (Subject Address,Attestation Type,Evidence). No placeholder-only fields on this route today.aria-input-field-name<label htmlFor>wiringcolor-contrastAxe report summary: 0 violations expected on
/attestations(no visual or ARIA wiring regressions; change is additive API onFormField).The new
SrOnlyLabelStorybook story is the canonical surface to axe-scan the placeholder-only pattern going forward.Keyboard-only walkthrough (
/attestations)aria-label="Submit Attestation").AddressInput→FormField).aria-label="Paste address from clipboard") → back to input flow.<select>(labelled "Attestation Type").<textarea>(labelled "Evidence"; placeholder is supplementary only).role="alert".All interactive elements remain reachable and operable without a pointer.
Screen reader (NVDA / Narrator pattern)
srOnlyLabel={true}: activating the field announces the hidden label text as the control name (verified viagetByRole('textbox', { name: 'Search' })unit test — DOM accessible name computation).srOnlyLabel={false}): behaviour identical to before; visible label is announced.aria-describedby.Colour contrast
No new colours, spacing, or radii introduced. Existing design tokens preserved.
Local test results
Test plan
FormFieldrenders visible label by default (no regression)srOnlyLabelappliessr-onlyclass to<label>srOnlyLabelpreserveshtmlFor/idassociationgetByRolewith{ name })Toggle+FormFieldcomposition still passesSelect+FormFieldcomposition still passesSrOnlyLabelstory addedcomponents.md,FORMS_AND_INPUTS.md)Accessibility checks (per
docs/ACCESSIBILITY.md)Branch & fork details
fix/issue-381-sr-only-form-labelsTopmatrixmor2014/Credence-FrontendCredenceOrg/Credence-Frontend:mainupstream/main(ae94019); clean single-commit PR, no conflicts expected.