Skip to content

fix(a11y): announce read-only state of form components to screen readers#2

Open
it-rec wants to merge 54 commits into
mainfrom
claude/carbon-issue-22407-qesd41
Open

fix(a11y): announce read-only state of form components to screen readers#2
it-rec wants to merge 54 commits into
mainfrom
claude/carbon-issue-22407-qesd41

Conversation

@it-rec

@it-rec it-rec commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Form components previously did not communicate their read-only state to
assistive technology, or did so using poorly-supported aria-readonly
or misapplied aria-disabled (which announced editable fields as
"disabled"). This violated WCAG 2.1 SC 4.1.2 (Name, Role, Value).

Each affected component now renders a visually-hidden "Read only"
description that is referenced from the focusable control via
aria-describedby, providing a reliable, cross-screen-reader
announcement. Misapplied aria-disabled on read-only Dropdown,
MultiSelect and Checkbox group controls is replaced so disabled is only
announced for genuinely disabled controls. aria-readonly is kept only
on roles that support it.

Covers React and Web Components packages:
Checkbox, CheckboxGroup, Dropdown, MultiSelect, FilterableMultiSelect,
NumberInput, RadioButton, RadioButtonGroup, Select, Slider, Toggle
(and fluid variants, which inherit the behavior).

Fixes carbon-design-system#22407

Form components previously did not communicate their read-only state to
assistive technology, or did so using poorly-supported `aria-readonly`
or misapplied `aria-disabled` (which announced editable fields as
"disabled"). This violated WCAG 2.1 SC 4.1.2 (Name, Role, Value).

Each affected component now renders a visually-hidden "Read only"
description that is referenced from the focusable control via
`aria-describedby`, providing a reliable, cross-screen-reader
announcement. Misapplied `aria-disabled` on read-only Dropdown,
MultiSelect and Checkbox group controls is replaced so disabled is only
announced for genuinely disabled controls. `aria-readonly` is kept only
on roles that support it.

Covers React and Web Components packages:
Checkbox, CheckboxGroup, Dropdown, MultiSelect, FilterableMultiSelect,
NumberInput, RadioButton, RadioButtonGroup, Select, Slider, Toggle
(and fluid variants, which inherit the behavior).

Fixes carbon-design-system#22407
@it-rec
it-rec force-pushed the claude/carbon-issue-22407-qesd41 branch from 9c4e182 to 9c74872 Compare June 10, 2026 06:13
it-rec and others added 28 commits June 19, 2026 06:05
Address review feedback: `aria-disabled=${disabled}` serialized the
boolean `false` to the string "false", rendering `aria-disabled="false"`
in the common (enabled) case. Use `ifDefined` so the attribute is
omitted unless the control is genuinely disabled, matching the
`aria-readonly`/`aria-describedby` pattern used elsewhere in this change.
Address Codecov patch-coverage gaps for this change:
- slider: add tests for the range (two-handle) and hidden-text-input
  (tooltip) thumb render paths so the readonly aria-readonly/
  aria-describedby attributes on all four thumbs are exercised.
- multi-select: assert the clear-selection button gets aria-disabled
  when the component is disabled, covering that branch.
Address review feedback (adamalston):
- CheckboxGroup: drop the fieldset-level "Read only" description and its
  aria-describedby entry. Each child Checkbox already announces read-only,
  so the group node caused a duplicate announcement.
- RadioButtonGroup: propagate the group's readOnly to each child
  RadioButton (unless the child sets it), so the announcement lands on the
  focusable radio inputs, and remove the now-redundant fieldset-level
  description. aria-readonly stays on the fieldset for group semantics.
Address review feedback (adamalston): the visually-hidden "Read only"
announcement was hardcoded. Make it translatable following Carbon's
i18n guidance.

React: each affected component now exposes translateWithId with a
carbon.<component>.read-only message id defaulting to "Read only"
(Checkbox, Toggle, RadioButton, Select gain the translateWithId API;
NumberInput and Slider extend their existing translation maps; Dropdown,
MultiSelect and FilterableMultiSelect widen their translateWithId key
union and fall back to the default).

Web Components: each affected component exposes a read-only-text
attribute / readOnlyText property defaulting to "Read only".

Adds unit tests asserting a custom translation overrides the default.
…em#22630)

* feat: add code connhect support for web components

* fix(web-components): update Code Connect snippets from review

* fix(web-components): align tooltip and toggle mappings

* chore: add tree-view issue note
…arbon-design-system#22632)

* chore(deps): bump github/codeql-action/analyze from 4.36.2 to 4.36.3

Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@8aad20d...54f647b)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.36.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: bump github/codeql-action/init to fix mismatch

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: devadula-nandan <47176249+devadula-nandan@users.noreply.github.com>
The NumberInput test helper throws on unknown message ids; add the new
carbon.number-input.read-only id so readOnly renders that pass a custom
translateWithId no longer throw.
…-system#22509)

* feat(react): overflowmenu contextual layout token cov

* feat(wc): overflowmenu contextual layout token cov

* fix: missing layout--size class

* chore: cleanup

* test: update tests and snapshots

* chore: add test stories

* fix: remove stale size attribute when removed at runtime

* fix: clear stale size on menu body/items

* chore: remove test stories

* docs: add TODO comment
* fix(popover): set color for tab tip button

* chore: update copyright year

* chore: set color

---------

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
…n-system#22657)

* fix(overflow-menu): preserve visible programmatic focus across browsers

* fix(overflow-menu): address review feedback

* fix(overflow-menu): include breadcrumb fallback focus styling
…rbon-design-system#22644)

* fix: flags scope merge issue

* docs: visualize feature flag scopes

* refactor: simplify

* chore: remove comment

* chore: clean up copyright year and comment

* Update packages/react/src/components/FeatureFlags/index.tsx

Co-authored-by: Adam Alston <aalston9@gmail.com>

* fix: re-attach js comment and hide stories

* chore: remove feature flags test story completly

---------

Co-authored-by: Adam Alston <aalston9@gmail.com>
…design-system#22275)

* fix(layout): update style modules to respect emit boundaries

* test(layout): cover utility emit boundaries

* fix(layout): emit web component size context classes

* fix(layout): restore layout context styles

---------

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
Co-authored-by: sangeethababu9223 <58620134+sangeethababu9223@users.noreply.github.com>
Co-authored-by: Sangeetha Babu <sangeetha9223@gmail.com>
…arbon-design-system#22651)

* fix(header): return explicit boolean value for header panel expanded

* chore: remove the true value

* chore: add test case for header panel

* chore: fix copyright date

* chore: update test file name and simplify

* chore: update copyright year

---------

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
…rbon-design-system#22681)

* chore(deps): bump github/codeql-action/init from 4.36.3 to 4.37.0

Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.3 to 4.37.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@54f647b...99df26d)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: upgrade github/codeql-action/analyze

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anna Wen <54281166+annawen1@users.noreply.github.com>
…gn-system#22679)

Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](actions/setup-java@1bcf9fb...0f481fc)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
carbon-design-system#22386)

* chore: add reproduction in storybook for testing

* fix: emit onInputValueChange on close button click

* Update packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx

Co-authored-by: Adam Alston <aalston9@gmail.com>

* fix: review comments

* Update packages/react/src/components/MultiSelect/__tests__/FilterableMultiSelect-test.js

Co-authored-by: Adam Alston <aalston9@gmail.com>

* chore: cleanup repro story and add additional assertion

---------

Co-authored-by: Adam Alston <aalston9@gmail.com>
dependabot Bot and others added 25 commits July 14, 2026 09:32
…system#22678)

Bumps [actions/stale](https://github.com/actions/stale) from 10.3.0 to 10.4.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](actions/stale@eb5cf3a...1e223db)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…design-system#22668)

* fix(Modal): preserve default dialog role on non-alert modals

With the enableDialogElement feature flag, a non-alert Modal rendered
role="" on the <dialog> element. An empty role hides the element's
implicit "dialog" role from assistive technology and breaks *ByRole
queries (e.g. cy.findByRole('dialog')); ComposedModal never sets role at
all. Emit undefined instead of an empty string so the native dialog role
is preserved, and only alert modals get role="alertdialog". The adjacent
aria-describedby had the identical empty-string pattern and is fixed too.

Adds regression tests asserting the non-alert dialog has no empty role
and that alert modals keep role="alertdialog".

Fixes carbon-design-system#22666

Signed-off-by: Kallinikos Milonakis <kallinikosmil@gmail.com>

* test(Modal): assert the accessible dialog role via getByRole

Address review: query getByRole('dialog') / getByRole('alertdialog') so
the tests fail if the implicit dialog role disappears (the actual
regression), rather than checking the raw attribute. Also drop the
history comment and align the describe title with the surrounding suite.

Signed-off-by: Kallinikos Milonakis <kallinikosmil@gmail.com>

* test(Modal): also assert the underlying role/aria-describedby attributes

Per review: keep the getByRole checks and additionally assert the
non-alert dialog renders no role/aria-describedby, and that the alert
dialog's aria-describedby points at the body content.

Signed-off-by: Kallinikos Milonakis <kallinikosmil@gmail.com>

---------

Signed-off-by: Kallinikos Milonakis <kallinikosmil@gmail.com>
…stem#22619)

* feat(feature-flags): add v12 release flag

* docs(v12): add v12 storybooks

* feat(storybook): add v12 storybook environments

* chore: update snaps

* fix(feature-flags): inherit v12 release overrides

* fix(web-components): remove feature flag attrs when a flag turns off

* chore(v12): incorporate storybook review feedback
…arbon-design-system#22661)

* refactor(dropdown): add query decorator for text container reference

* fix: update copyright year to 2026
Co-authored-by: sangeethababu9223 <58620134+sangeethababu9223@users.noreply.github.com>
…-design-system#22658)

* refactor(content-switcher): replace  with  decorator

* refactor(content-switcher): added new unit test cases

* refactor(content-switcher): removed irrelevent unit test cases
…rbon-design-system#21861)

* the allowCustomValue block now checks the currently

* added a unit test asserting that with allow-custom-value + value=item1

* chore(prettier): format

* fix(combo-box): preserve selected value on open and added tests

* test(combo-box): keep only wired regression coverage

---------

Co-authored-by: Kenny Lam <909118+kennylam@users.noreply.github.com>
Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
Co-authored-by: “heloiselui” <helolui27@gmail.com>
…or preview/unstable variant (carbon-design-system#22617)

* feat: add pageSelectRenderer, deprecate notice on unstable pagination

* feat: pagination renderPageSelect support and deprecate unstable

* test: update public api

* test: add render prop test coverage

* fix: review comments

* docs: update doc for pagesUnknow

* fix: review comments

* refactor: commit suggested changes

* Update packages/react/src/components/Pagination/Pagination.tsx

Co-authored-by: Adam Alston <aalston9@gmail.com>

* chore: remove the example story for renderPageSelect

---------

Co-authored-by: Adam Alston <aalston9@gmail.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
…-system#22698)

* docs: add long-term support release guidance

* fix: formatting

* docs: add products libs to release schedule

* ci: notify Slack when main CI fails
* fix(deps): update dependency chalk to v5

* fix(deps): support chalk 5 in postinstall scripts

Chalk 5 is ESM-only, so the CommonJS postinstall scripts in
carbon-components and carbon-components-react cannot use require('chalk').
Replace the synchronous require with an async function that obtains
chalk via dynamic import(), which is the supported CJS→ESM bridge.

Also dedupe yarn.lock so all chalk ranges resolve to 5.6.2.

Add postinstall regression tests under each package's __tests__/
directory. The tests spawn the script in a child Node process with
FORCE_COLOR=0 and assert: exit 0, package name in stderr, deprecation
URL in stderr, and no TypeError.

* Apply suggestions from code review

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Taylor Jones <taylor.jones826@gmail.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Co-authored-by: Mahmoud <132728978+maradwan26@users.noreply.github.com>
Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
…stem#22696)

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
…arbon-design-system#22680)

Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 3.0.3 to 3.0.5.
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Changelog](https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md)
- [Commits](slackapi/slack-github-action@45a88b9...0d95c9a)

---
updated-dependencies:
- dependency-name: slackapi/slack-github-action
  dependency-version: 3.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…gn-system#21953)

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
Co-authored-by: Mahmoud <132728978+maradwan26@users.noreply.github.com>
…design-system#22687)

* feat(code-connect): remaining web components support

* fix(react): various fixes, typos, etc

* fix: use static IconName

---------

Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
* feat(icons): new Icons July 2026 (3)

* update(icons): updated Icons July 2026 (3)

Moving 2 UI icons from July 2026 and updated categories. All additions and updates approved by BXD.

### Changelog

**Moved**

`Navigation` → `Systems`
- [x] 32/gateway--inclusive.svg
- [x] 32/gateway--parallel.svg

* chore(jest): update snapshots

---------

Co-authored-by: Kenny Lam <909118+kennylam@users.noreply.github.com>
…sign-system#22688)

* chore(deps): replace dependency @hapi/joi with joi ^17.1.1

* chore(yarn): dedupe

* chore(deps): update Joi imports for new package name

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Kenny Lam <909118+kennylam@users.noreply.github.com>
* fix(storybook): restore v12 overview pages

* fix(storybook): restore v12 overview pages
…system#22707)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
* fix(react-popover): close on Esc

* fix(wc-popover): close on Esc

* chore: cleanup comments

* fix: ci

* fix: add defaultPrevented

* fix: close innermost only when nested

* fix: wc shadow nesting

* docs: comments

* fix: trigger focus return

* fix: docs
* feat(tokens): dtcg explorations

* feat(tokens): dtcg explorations

* feat(tokens): remove generative script for developemnt

* feat(tokens): remove js to json converter script one time use only

* feat(tokens): component token issue fix

* feat(tokens): updated_token.scc reference

* feat(themes): add DTCG schema validation test

- Add comprehensive DTCG schema validation test suite
- Validates all theme token files (white, g10, g90, g100)
- Validates all component token files
- Fetches and validates against official DTCG schema
- Includes preprocessing for Carbon-specific patterns
- All tokens now pass 100% DTCG compliance

* chore: update yarn.lock for new dependencies

* fix: dedupe

* fix: preserve hex codes

* feat(tokens): generator update

* chore: added parity tests and snapshot updates

* fix: button json

* feat(tokens): remove js based tokens and add dtcg generate js tokens

* fix: escape backslashes in toSource string serialisation

* chore: update yarn.lock after upstream/main merge

* chore: dedupe yarn.lock

* chore: fix comment accuracy in index.ts

* chore: squash merge feat/dtcg-with-color-aliases

* fix(themes): emit .d.ts alongside generated JS token files

The build:js-tokens step generates JS files into js/generated/ outside
the src/ directory. Without sibling .d.ts files, TypeScript had to compile
those JS files directly, which violated rootDir: "./src" in
tsconfig.types.json (TS6059) and broke the entire build chain.

Each generator now writes a .d.ts alongside its .js output so TypeScript
resolves types from the declarations without pulling the JS into
compilation. This keeps rootDir: "./src" and lib/index.d.ts unchanged.

* feat(themes): update DTCG token definitions for components and themes

- Updated button, content-switcher, notification, status, and tag component tokens
- Updated theme tokens for white, g10, g90, and g100 themes

* docs(themes): update DTCG README and package.json

* docs(themes): update DTCG README with additional context

* fix: refactoring

* fix(themes): use org.carbon extension namespace in DTCG converter

* chore(e2e): update icons and pictograms public API snapshots

* chore(themes): update DTCG snapshot for rgba alpha output

---------

Co-authored-by: Riddhi Bansal <41935566+riddhybansal@users.noreply.github.com>
Co-authored-by: riddhybansal <riddhybansal@gmail.com>
…m#22063)

* fix(deps): update dependency downshift to v9.3.2

* fix(deps): update dependency downshift to v9.4.0

* chore: yarn dedupe

* chore: yarn format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Riddhi Bansal <41935566+riddhybansal@users.noreply.github.com>
Co-authored-by: “heloiselui” <helolui27@gmail.com>
Co-authored-by: Heloise Lui <71858203+heloiselui@users.noreply.github.com>
…n-system#22716)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ign-system#22717)

Signed-off-by: Roman178 <38655430+Roman178@users.noreply.github.com>
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.

[a11y]: SR does not announce readonly status of form elements