Skip to content

fix(accessibility): properly set the label on Listbox when used with FormField - #6780

Open
ttcchhmm wants to merge 1 commit into
nuxt:v4from
Departement-de-Maine-et-Loire:v4
Open

fix(accessibility): properly set the label on Listbox when used with FormField#6780
ttcchhmm wants to merge 1 commit into
nuxt:v4from
Departement-de-Maine-et-Loire:v4

Conversation

@ttcchhmm

Copy link
Copy Markdown

🔗 Linked issue

Resolves #6756.

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

This PR fixes the missing ARIA attribute needed to link the label provided by UFormField to a child UListbox. Since the component within the UListbox with role="listbox" is a div, simply using the for attribute on the label won't work as divs are not labelable. To work around that, I added an ID to the main label (like the one used for hints and descriptions) within UFormField and used it with aria-labelledby in UListbox. This allows the label to properly show within the accessibility tree.

Screenshot of the Chromium DevTools window showing the accessibility tree, where the listbox element have the proper 'My listbox' label with the aria-labelledby attribute set to v-13-label

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Copilot AI review requested due to automatic review settings July 30, 2026 11:13
@ttcchhmm
ttcchhmm requested a review from benjamincanac as a code owner July 30, 2026 11:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the v4 #4488 label Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

FormField now assigns an id to its rendered label using ${ariaId}-label. Listbox uses the default useFormField binding behavior and conditionally sets aria-labelledby on ListboxContent to reference the generated label id.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the accessibility fix for associating a FormField label with Listbox.
Description check ✅ Passed The description matches the change and explains the missing ARIA label association fix.
Linked Issues check ✅ Passed The changes add label IDs and aria-labelledby wiring, satisfying issue #6756's accessibility goal.
Out of Scope Changes check ✅ Passed The diff is narrowly focused on the FormField/Listbox label association fix with no obvious unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/runtime/components/Listbox.vue`:
- Line 378: Update the Listbox component’s aria-labelledby binding on
ListboxContent to use the injected FormField label id rather than the control
id, and only set it when a label is actually rendered. Preserve no reference for
standalone Listboxes or FormFields without labels, and add regression coverage
for custom ids and unlabeled usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fa30d2a7-0f28-4149-ada7-890f2a4accbd

📥 Commits

Reviewing files that changed from the base of the PR and between c4b786c and 65fd604.

⛔ Files ignored due to path filters (6)
  • test/components/__snapshots__/AuthForm-vue.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/AuthForm.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/FormField-vue.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/FormField.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/Listbox-vue.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/Listbox.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • src/runtime/components/FormField.vue
  • src/runtime/components/Listbox.vue

</ListboxFilter>

<ListboxContent data-slot="content" :class="ui.content({ class: props.ui?.content })">
<ListboxContent data-slot="content" :class="ui.content({ class: props.ui?.content })" :aria-labelledby="id !== undefined ? `${id}-label` : undefined">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Derive aria-labelledby from the FormField label id, not the control id.

When a Listbox supplies a custom id, Line 213 makes id differ from FormField’s stable ariaId; this emits ${customId}-label, while FormField renders ${ariaId}-label. Standalone Listboxes with explicit ids, and FormFields without labels, can also receive dangling ARIA references. Expose/use the injected label id and bind it only when a label is rendered; add regression tests for both cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/runtime/components/Listbox.vue` at line 378, Update the Listbox
component’s aria-labelledby binding on ListboxContent to use the injected
FormField label id rather than the control id, and only set it when a label is
actually rendered. Preserve no reference for standalone Listboxes or FormFields
without labels, and add regression coverage for custom ids and unlabeled usage.

@pkg-pr-new

pkg-pr-new Bot commented Jul 30, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@nuxt/ui@6780

commit: 65fd604

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UFormField label is not associated to a child UListbox

2 participants