Each row in a Likert element gets an aria-labelledby pointing at the row's question label (the fix from #3001852: likert radio buttons needs aria-labelledby attr for accessibility), but that's still the only thing wired up - every radio in the row ends up with the identical accessible name.

There's nothing tying an individual radio to its column ("Low" vs. "Medium" vs. "High").

Practical effect: a screen reader user tabbing through one row's radios (control-to-control, not cell-to-cell) hears the same question announced 5-6 times in a row with no way to tell which answer is which. Users who navigate the table cell-by-cell are fine, since the <td>'s own computed name does concatenate row + column — it's specifically the <input> that's missing it.

Steps to reproduce

  1. Create a webform with a Likert element, 2+ questions, 3+ scale options.
  2. Tab through one row's radios with a screen reader — control to control, not cell to cell.
  3. Every radio in the row announces the identical name.

Confirmed on 6.3.0. I also checked #3001852: likert radio buttons needs aria-labelledby attr for accessibility and #2982067: [accessibility] Elements must have labels. (includes select other, color, likert, multiple, and table select) but both are closed and already in this release, neither covers this. Row-only aria-labelledby needs to also pick up the column header so each radio's name is "{question} — {answer}", not just "{question}".

AI disclosure: Drafted with help from Claude Code while auditing my own site for accessibility issues.

CommentFileSizeAuthor
#8 3621031 after.png985.38 KBcsakiistvan
#8 3621031 before.png714.95 KBcsakiistvan

Issue fork webform-3621031

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

ultimike created an issue. See original summary.

liam morland’s picture

Version: 6.3.0 » 6.3.x-dev
Issue tags: -a11y +Accessibility

andres alvarez made their first commit to this issue’s fork.

andres alvarez’s picture

Confirmed the root cause. Every radio in a Likert row sets aria-labelledby to only the row's question id (src/Element/WebformLikert.php, inside processWebformLikert()). Per the WAI-ARIA accessible-name algorithm, aria-labelledby on a form control overrides its associated &lt;label&gt; entirely, so the per-radio visually-hidden answer text (already present in the markup, wrapped as a &lt;label&gt;) is never used for the accessible name. Every radio in a row ends up announcing the identical question text, regardless of which answer/column it represents.

The fix gives each answer/column header cell a unique id (same Html::getUniqueId() pattern already used for the question id) and has each radio's aria-labelledby reference both the question id and its own column's header id, so the computed accessible name becomes "question answer" rather than "question" alone.

Updated the functional test's hardcoded markup assertions and added an explicit assertion that two radios within the same question row resolve to different aria-labelledby values. Confirmed the new assertion fails against the unpatched code and passes with the fix.

MR to follow.

andres alvarez’s picture

Status: Active » Needs review
csakiistvan’s picture

Assigned: Unassigned » csakiistvan
csakiistvan’s picture

Assigned: csakiistvan » Unassigned
Status: Needs review » Reviewed & tested by the community
StatusFileSize
new714.95 KB
new985.38 KB

✅ Tested and works — applied MR !939 on top of 6.3.x (e0f2f213b), ran drush cr and reloaded a webform with a Likert element (2 questions, 3 answers): before the patch all three radios in a row carried aria-labelledby="edit-satisfaction-table-q1-likert-question", after it each answer column header gets its own id and every radio references question + its own column (...-q1-likert-question edit-satisfaction-table-header-2), so the radios in a row no longer share one accessible name.