Skip to content

Issue/1794#1889

Open
MaryamMehd wants to merge 20 commits intomainfrom
issue/1794
Open

Issue/1794#1889
MaryamMehd wants to merge 20 commits intomainfrom
issue/1794

Conversation

@MaryamMehd
Copy link
Copy Markdown
Collaborator

No description provided.

…edby (#1640)

This commit implements accessibility improvements by associating instructional
text with their parent form fields using the aria-describedby attribute.

Changes:
- Modified ItemFieldGrid to recursively add aria-describedby to input/textarea
  elements and radio/checkbox groups when instructions are present
- Added getInstructionsId helper function to generate instruction IDs
- Updated DisplayInstructions component to accept an optional id prop
- Added Storybook tests for String, Boolean, and Text items to verify
  aria-describedby functionality with instruction text

Screen readers will now announce instructional text when a field receives focus,
improving the accessibility experience for users with visual impairments.

Fixes #1640
…edby

- Apply aria-describedby directly to MUI components via their props
- For text fields (String, Text): Use slotProps.input to add aria-describedby
- For radio buttons (Boolean): Use inputProps on individual radio inputs
- Updated ChoiceRadioSingle to accept and forward ariaDescribedBy prop
- Removed dynamic React element cloning from ItemFieldGrid
- Consolidated accessibility tests in Testing/Accessibility/Instructions
- Fixed automated Storybook tests for accessibility verification
- All three item types (String, Text, Boolean) properly announce instructions via VoiceOver

Fixes #1640
- Fixed lint error blocking CI/CD
- Rebased issue/1640 on latest main
- Verified aria-describedby with VoiceOver testing
- Instructions announced correctly when field gets focus

Fixes #1640
…1640)

Address reviewer feedback for Issue #1640 by implementing proper aria-describedby
support and adding comprehensive VoiceOver accessibility tests.

## Changes Made:

### Bug Fixes (from reviewer feedback):
1. **Fixed slotProps placement**: Changed from slotProps.input to slotProps.htmlInput
   in StringField and TextField components to correctly apply aria-describedby to
   the actual input/textarea elements instead of wrapper divs

2. **Fixed test selector**: Updated StringInstructionsAccessibility story to query
   for 'input' instead of 'textarea' for string fields

3. **Removed unnecessary type**: Removed 'aria-describedby'?: string type from
   Radio.styles.tsx as the attribute is passed via inputProps

### Feature Implementation:
4. **Added aria-describedby support** to the following item types:
   - Integer (IntegerField & IntegerItem)
   - Decimal (DecimalField & DecimalItem)
   - DateTime (DateTimeField, CustomDateTimeItem, CustomDateField, CustomDateItem)
   - String (already working, fixed slotProps)
   - Text (already working, fixed slotProps)
   - Boolean (already working)

   Pattern: Each field component now accepts instructionsId prop and applies it
   via slotProps.htmlInput with aria-describedby attribute

### Test Coverage:
5. **Added VoiceOver accessibility test stories** for all item types:
   - IntegerInstructionsAccessibility
   - DecimalInstructionsAccessibility
   - QuantityInstructionsAccessibility
   - UrlInstructionsAccessibility
   - AttachmentInstructionsAccessibility
   - DateInstructionsAccessibility
   - DateTimeInstructionsAccessibility
   - TimeInstructionsAccessibility
   - ChoiceInstructionsAccessibility
   - OpenChoiceInstructionsAccessibility

## Testing:
- ✅ IntegerInstructionsAccessibility - VoiceOver confirmed working
- ✅ DecimalInstructionsAccessibility - VoiceOver confirmed working
- ✅ DateTimeInstructionsAccessibility - VoiceOver confirmed working
- ✅ BooleanInstructionsAccessibility - VoiceOver confirmed working
- ✅ StringInstructionsAccessibility - Fixed and working
- ✅ TextInstructionsAccessibility - Fixed and working

## Remaining Work (for future commits):
The following item types still need aria-describedby implementation:
- Date (has error to fix)
- Quantity
- Time
- URL
- Attachment
- Choice
- Open-Choice

These follow the same pattern and will be addressed in subsequent commits.

Refs #1640

Made-with: Cursor
…sue #1640)

Implements accessibility instructions for URL and Quantity fields by adding instructionsId prop support. For Quantity items, aria-describedby is applied to both the value input field and unit selector to ensure instructions are announced regardless of which field receives focus first.

Made-with: Cursor
…(Issue #1640)

Fixes 'Cannot access feedback before initialization' error by ensuring feedback is defined before being used to generate instructionsId.
…ibility (Issue #1640)

Problem:
MUI TimePicker and Autocomplete components have complex internal structures that
prevent aria-describedby from being properly announced by VoiceOver.
- TimePicker uses segmented inputs (separate spans for hours, minutes, AM/PM)
- Autocomplete has nested internal elements (button + hidden input + listbox)

Solution:

1. CustomTimeItem (Time field)
   - Created CustomTimeItem.tsx using existing CustomTimeField component
   - CustomTimeField uses standard TextField + MUI Select dropdown (not TimePicker)
   - Matches pattern from CustomDateItem (which works successfully)
   - Added instructionsId prop support to CustomTimeField
   - Updated SingleItemSwitcher to use CustomTimeItem instead of TimeItem

2. CustomChoiceSelectField (Choice Select dropdown)
   - Created CustomChoiceSelectField.tsx using standard MUI Select (not Autocomplete)
   - Applied aria-describedby and aria-labelledby directly to Select component
   - MUI Select passes these attributes through to internal focusable button element
   - Added useRenderingExtensions and getInstructionsId to ChoiceSelectAnswerOptionItem
   - Updated ChoiceSelectAnswerOptionView to use CustomChoiceSelectField

3. Supporting Changes
   - Added instructionsId support to CustomTimeField for DateTime items
   - Updated DateTimeField to pass instructionsId to CustomTimeField
   - Added instructionsId prop threading for Choice Radio fields

Testing:
Both implementations successfully tested with VoiceOver.

Related to: #1640

Made-with: Cursor
Problem:
Attachment fields have multiple focusable elements (file upload button, URL field,
filename field) but VoiceOver was not reading the accessibility instructions when
users navigated to the field.

Solution:
Applied aria-describedby directly to the file upload button (first focusable element),
following the same successful pattern used for Choice Select fields where MUI
components need aria attributes on the actual interactive element, not wrapper groups.

Changes:
- AttachmentItem: Added useRenderingExtensions and getInstructionsId to generate
  instructionsId from rendering extensions
- AttachmentFieldWrapper: Added instructionsId and itemText props, passed to
  AttachmentField
- AttachmentField: Added role="group" wrapper with aria-labelledby/aria-describedby
  and passed instructionsId to AttachmentFileCollector
- AttachmentFileCollector: Applied aria-describedby to the IconButton (Attach file)
- Improved UX: Made explanatory text smaller, lighter, and italic to distinguish
  from user-defined instructions

Testing:
VoiceOver successfully reads the instructions when focusing the Attach file button.

Related to: #1640

Made-with: Cursor
…rking yet)

Problem:
- Open-Choice Autocomplete fields do not announce instructions to screen readers
- VoiceOver only reads "Occupation, list box popup collapsed, edit text" without the instructions

Attempted solution:
- Added useRenderingExtensions and getInstructionsId to OpenChoiceAutocompleteItem
- Passed instructionsId down to OpenChoiceAutocompleteField
- Attempted to apply aria-describedby via slotProps.input.inputProps

Current status:
- aria-describedby is NOT being applied to the textarea element
- MUI Autocomplete has complex internal structure that does not properly propagate aria attributes
- Similar issue to Time and Choice fields that required custom implementations

Next steps:
- Create CustomOpenChoiceField.tsx component (similar to CustomTimeItem and CustomChoiceSelectField)
- Use standard MUI Select + TextField to support both predefined options and custom text input
- This will properly support aria-describedby for accessibility

Files modified:
- OpenChoiceAutocompleteItem.tsx: Added instructionsId generation
- OpenChoiceAutocompleteField.tsx: Attempted aria-describedby implementation (incomplete)

Related issue: #1640

Made-with: Cursor
…OpenChoiceField

Problem:
- Open-Choice fields did not announce instructions to screen readers
- MUI Autocomplete has complex internal structure that does not propagate aria-describedby
- VoiceOver only read field name without instructions

Solution:
Created CustomOpenChoiceField component following Time and Choice patterns:
- Uses MUI Select dropdown for predefined Coding options
- Includes custom value option that reveals TextField for custom text input
- Properly applies aria-describedby to both Select and TextField elements

Changes:
1. Created CustomOpenChoiceField.tsx with Select + TextField
2. Updated OpenChoiceAutocompleteItem.tsx to use CustomOpenChoiceField
3. Updated OpenChoiceSelectAnswerOptionItem.tsx to use CustomOpenChoiceField
4. Updated AccessibilityInstructions.stories.tsx test for new component

Testing:
- VoiceOver correctly reads instructions for Open-Choice dropdown
- VoiceOver reads instructions for custom text input field
- All functionality working as expected

Related issue: #1640

Made-with: Cursor
…ctors

Align story test utilities and selectors with current renderer DOM behavior, remove lint-blocking issues, and harden Storybook CI startup/timeout settings to avoid flaky connection and interaction failures.

Made-with: Cursor
Revert unintended custom choice/open-choice/time control swaps and align instruction announcements across control variants for consistent VoiceOver behavior in storybook and 715 testing.

Made-with: Cursor
- Expose aria-describedby on slider for instructions in tests\n- Time/choice/slider-related story plays and testUtils (MUI TimePicker via clock)\n- AccessibilityInstructions and Time stories; package.json CI test timeout if changed
Apply eslint --fix formatting in testUtils and AccessibilityInstructions
stories so CI lint passes.

Made-with: Cursor
Pass aria-describedby through slotProps.input so screen readers use the
focused thumb input. Align SliderItem with IntegerItem using
useRenderingExtensions and ItemFieldGrid feedback.
…le and item.prefix

Implements text styling (rendering-style, rendering-markdown, rendering-xhtml) for
Questionnaire.title and Questionnaire.item.prefix as specified in the Advanced Rendering
Questionnaire profile. Closes #1794.

New components:
- QuestionnaireTitleText: renders Questionnaire.title via StyledText, honouring
  _title rendering extensions; exported from the renderer package and wired into
  RendererHeader and QuestionnairePopoverMenu
- ItemPrefixSwitcher: renders item.prefix via StyledText, honouring _prefix rendering
  extensions; integrated into ItemLabel, GroupHeading, GridRow, FormBodySingleTab and
  FormBodySingleCollapsible

Supporting changes:
- itemHasLabelHeadingContent() utility: group/table/repeat headings now appear when a
  prefix exists even if item.text is absent
- CalculatedExpression.from extended with 'item._prefix'; getCalculatedExpressions() and
  useDisplayCqfAndCalculatedExpression() updated so CQF/calculatedExpression extensions
  on _prefix are evaluated at runtime

Tests added:
- itemTextToDisplay.test.ts: itemHasLabelHeadingContent (4 cases)
- getExpressionsFromItem.test.ts: calculatedExpression and cqf-expression on _prefix,
  combined item / _text / _prefix extraction (3 cases)
- useDisplayCqfAndCalculatedExpression.test.ts: item._prefix source resolution (2 cases)

Storybook stories added under SDC / 9.1.1 Rendering > Text Appearance:
- RenderingStyleTitle, RenderingMarkdownTitle, RenderingXHTMLTitle
- RenderingStylePrefix, RenderingMarkdownPrefix, RenderingXHTMLPrefix
- PrefixOnlyNoText (edge case: group heading driven solely by a styled prefix)

Made-with: Cursor
Made-with: Cursor

# Conflicts:
#	packages/smart-forms-renderer/src/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.tsx
These test files were added via the merge from main and contained an
unused 'Await' import from react-router-dom, causing TS6133 errors in CI.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants