Skip to content

EPBDS-16211: a select strips the 34 Semantic props it ignored, and table-cell fields and slider handles have names - #206

Merged
AlexSamBY merged 2 commits into
masterfrom
select-parity-a11y
Oct 12, 2026
Merged

AlexSamBY merged 2 commits into
masterfrom
select-parity-a11y

Conversation

@AlexSamBY

Copy link
Copy Markdown
Member

What

The select-parity and accessibility items of the 2026-10-08 audit.

A select strips the 34 Semantic props it ignored

semantic-ui-react's Dropdown declared 65 props, a list taken from the 0.34.3 bundle's handledProps. Of those:

Props Fate
16 read by the wrapper or the listbox
12 already among the 14 dropped by decision
onClick, onFocus still reach the dropdown element and work there
children ignored
the remaining 34 read by nothing, so each reached the dropdown element as an attribute, a boolean one with React's "Received true for a non-boolean attribute" warning

The 34 join DROPPED_PROPS, grouped as the file groups them:

  • Open, close and select machinery. The WAI-ARIA select-only combobox pattern decides these now: closeOnBlur, closeOnChange, closeOnEscape, defaultOpen, open, openOnFocus, selectOnBlur, selectOnNavigation, wrapSelection, defaultUpward, direction, and tabIndex, which on the dropdown would add a second tab stop.
  • Style variants: basic, button, floating, fluid, inline, item, labeled, loading, pointing, scrolling, simple.
  • What served search and multiple: defaultSearchQuery, minCharacters, defaultSelectedLabel, selectedLabel, renderLabel, onLabelClick.
  • Element overrides: as, header, trigger, text, defaultValue.

They behave as the existing dropped names do:

  • they are stripped, with a warning once per name in a development run;
  • validateMeta reports them, since it reads the same list;
  • docs/SUPPORTED-PROPS.md's Dropped table gives what each did.

Neither the examples nor the consumer-only record (META_ATTRIBUTES, CONSUMER_ONLY_ATTRIBUTES) uses one. The engine passes none of them to a select: the form adapter reads defaultValue before the select renders, and the mapper consumes renderLabel.

A field in a table cell is named by its column's header

A field in a cell rarely has a label, and a screen reader does not name a field after the header above it. So such a field had no accessible name at all. It now takes the header's label, when the header shows that label as plain text, as its aria-label, by each way a row is drawn:

  • A header's renderCell. TableView passes the column as a fifth renderer argument. transforms.ts gives it to a field definition that names nothing: an Input, Select, Dropdown, Checkbox, Toggle or SliderLabel with no label, aria-label or aria-labelledby.
  • A TableCells row, through a TableColumnsContext that TableView provides around its body.
  • The draft row of a localDraft Data (LocalDraftTableRow), through the same context.

For the last two, a field is named only when the row has a cell per header, so a misaligned row is never named wrongly. Other renderers ignore the new argument, so nothing new reaches the DOM.

A slider's handles have names

A handle is named by the field's label, translated, or by its name. A range's two handles add ", minimum" and ", maximum", after the WAI-ARIA multi-thumb slider pattern. A meta's own aria-label or aria-labelledby wins, and goes to the handles instead of the element around them.

config.md gains "A control's accessible name". The changelog has two Accessibility entries and one under "Props removed".

Measured

  • The ledger of nameless controls in the demo examples goes 66 → 14:

    • 46 table-cell fields in nestedDataKind and tableForm;
    • 6 slider handles.

    What is left: 9 icon buttons in columns whose header has no label, layout's two hidden tabs, two buttons of all, and one field in tableExtraItems' extraItems row, whose cells the mapper builds without their columns.

  • The DOM snapshots change by exactly those 52 aria-labels: "SKU", "Qty", "Unit Price", "Start Date", "volume", "priceRange, minimum" and so on.

  • table-cell-names.test.js, 6 tests. Four of them fail with master's TableView, mapper, transforms and LocalDraftTableRow: the three paths, and a TableCells row renamed when its header changes. The two tests that check no name is given pass either way.

  • Dropdown.test.js. Its test that dropped props stay off the DOM now passes fluid, closeOnBlur, open, tabIndex, text and as as well. With master's Dropdown.tsx it finds 4 extra attributes on the element.

  • Local gates on HEAD, all exit 0. That is all 22 gates plus the manifest contract, on Node 24.14.0.

  • The run before failed twice, and both are dealt with:

    • TableView.tsx's statement coverage fell short of its 100% threshold. The test for a renamed header, added since, covers the line it missed.
    • test:react19 lost a jest worker to SIGSEGV in gen-ts.contract.test.js, with all 2787 of its tests passing (Crash in V8 GC on v24.x and earlier nodejs/node#62393).

🤖 Generated with Claude Code

…ble-cell fields and slider handles have names

Select parity and accessibility items of the 2026-10-08 audit:
- Dropdown's DROPPED_PROPS gains the 34 names semantic-ui-react declared that the listbox neither read
  nor stripped: its open, close and select machinery, its style variants, what served search and
  multiple, and its element overrides. Each reached the dropdown element as an attribute, a boolean
  one with React's warning. They are stripped with the development warning the others have,
  validateMeta reports them, and docs/SUPPORTED-PROPS.md says what each did. Neither corpus uses one.
- A field in a table cell that names nothing takes its column header's label as its aria-label:
  through a header's renderCell (a fifth renderer argument, the column), a TableCells row or a
  localDraft draft row (TableColumnsContext), the last two only when the row has a cell per header.
- A slider's handles are named by the field's label or name, a range's with ", minimum" and
  ", maximum"; a meta's own aria-label or aria-labelledby goes to the handles.
The ledger of nameless controls in the demo examples goes from 66 to 14: 46 table-cell fields and
6 slider handles. config.md says how a control gets its name.
# Conflicts:
#	src/demo/examples/__tests__/__snapshots__/examples.dom-contract.test.js.snap
#	src/demo/markdowns/changelog.md
@AlexSamBY
AlexSamBY merged commit 5394a9c into master Oct 12, 2026
7 checks passed
@AlexSamBY
AlexSamBY deleted the select-parity-a11y branch October 12, 2026 08:42
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.

1 participant