Skip to content

fix(Range): forward aria attributes to the thumb - #466

Merged
IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-d6c3802a
Aug 22, 2026
Merged

fix(Range): forward aria attributes to the thumb#466
IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-d6c3802a

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Linked issue

Sync with nuxt/ui@v4 — the last three commits of the queue, contiguous (§6 4b): d6c3802a (nuxt/ui#6848) · f62aa143 (no-op) · aa5f4af0. Follows #464. After this the cursor is at upstream HEAD.

Type of change

  • Bug fix (a non-breaking change that fixes an issue)
  • Documentation (updates to the documentation or readme)

Description

d6c3802a — the caller's aria-* never reached the thumb

Upstream's Slider is this fork's Range; the reka primitives keep their own names, so only the wrapper differs. This is the second commit in that family — #431 already moved useFormField's derived attributes onto the thumb. What still did not get there was the caller's own aria-*: v-bind="rootProps" put them on SliderRoot, which is not the element with role="slider". A screen reader announcing the thumb read Reka UI's placeholder name Thumb, while the author's aria-label sat on a wrapper that announces nothing.

The fix stops inheriting attributes (inheritAttrs: false) and routes six by hand — aria-label, aria-labelledby, aria-describedby, aria-valuetext, aria-invalid, aria-errormessage:

  • One thumb — the six go to the thumb (pick), everything else stays on the root (omit). The 'Thumb' fallback applies only when the caller gave neither a label nor a labelledby.
  • Several thumbs — they stay on the root, because Reka UI already names each thumb by position (Minimum/Maximum, or Value n of m) and overwriting that with one repeated label would make the thumbs indistinguishable. The root takes role="group" so the caller's label names the control as a whole — unless the caller supplied a role, which wins.

Our Range.vue matched upstream's pre-image on both thumb lines and on the SliderRoot binding, so the diff applies unchanged apart from uib24ui and UTooltipB24Tooltip. pick/omit already exist in ../utils. The docs tip is ported to range.md with the component renamed.

f62aa143 — no-op

Upstream's release bookkeeping (version bump + generated changelog). This fork has its own release train and its CHANGELOG.md is generated from our commits. Same call as the five previous upstream release commits in the ledger.

aa5f4af0 — badges

Housekeeping after 4.11.0 shipped: "coming" badges become what happened. The shape transfers, but every value is fork-specific, and each was checked against this repo's tags with git tag --contains rather than assumed to match upstream's timing:

upstream here why
Soon4.11+ on componentDetection Soon2.12+ 530b9616 (#396) is in no tag before v2.12.0
drop New from input-rating.md dropped d08b5830 (#283) shipped in v2.10.0 — two releases back, stale here too
SoonNew on splitter.md badge added 62a2acc8 (#441) first appears in v2.12.0; our page never had one
SoonNew on progress-group.md badge added same, #443
remove the ::note "Soon" badges nothing to remove #464 ported those notes without the badge, precisely because this commit deletes it

Left alone: calendar.md, drawer.md, modal.md, slideover.md and the two With external scroll element badges — this fork's own markers on sections upstream's commit does not mention.

Verification

By mutation, not by a passing suite. Upstream's 14 aria cases and 2 render cases are ported; with Range.vue reverted and the tests kept, 11 of the 14 fail, plus all 3 affected render cases. The 3 that pass either way pin behaviour that was already right — the 'Thumb' fallback, not grouping an unlabelled range, leaving non-aria attributes on the root — and are kept as regression pins rather than counted as evidence for this change.

Badges checked in the built navigation data rather than in the markdown: splitter and progress-group carry New, input-rating no longer does, scroll-area is untouched, and 2.12+ renders on the Vue installation page.

Gate with CI=true: dev:prepare · lint · typecheck · test (7016 passed, 6 skipped, 308 files) · build · docs:generate.

Ledger: cursor → aa5f4af0, which is upstream HEAD; three entries with their .sync/log/ journals; parity snapshot refreshed (one line, zero package differences).

Checklist

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

Generated by Claude Code

Ports three upstream commits, contiguous in `v4` (§6 4b):
`d6c3802a` (nuxt/ui #6848) · `f62aa143` (no-op) · `aa5f4af0`.

**`d6c3802a`, against `Range`.** Upstream's `Slider` is this fork's `Range`; the
reka primitives keep their own names, so only the wrapper differs. This is the
second commit in that family — `f3c2ac21` (#431) already moved `useFormField`'s
derived attributes onto the thumb. What still did not get there was **the
caller's own** `aria-*`: `v-bind="rootProps"` put them on `SliderRoot`, which is
not the element with `role="slider"`. A screen reader announcing the thumb read
Reka UI's placeholder name `Thumb` while the author's `aria-label` sat on a
wrapper that announces nothing.

The fix stops inheriting attributes and routes six of them by hand. With one
thumb they go to the thumb and everything else stays on the root; the `'Thumb'`
fallback applies only when the caller gave neither a label nor a `labelledby`.
With several thumbs they stay on the root, because Reka UI already names each
thumb by position (`Minimum`/`Maximum`, `Value n of m`) and one repeated label
would make them indistinguishable — the root takes `role="group"` instead, unless
the caller supplied a `role`, which wins.

Our `Range.vue` matched upstream's pre-image on both thumb lines and on the
`SliderRoot` binding, so the diff applies unchanged apart from `ui`→`b24ui` and
`UTooltip`→`B24Tooltip`. `pick`/`omit` already exist in `../utils`.

**`f62aa143`** is a no-op: upstream's release bookkeeping. This fork has its own
release train and its `CHANGELOG.md` is generated from our commits.

**`aa5f4af0`** turns upstream's "coming" badges into what shipped. The shape
transfers; every value is fork-specific, and each was checked against this
repo's tags with `git tag --contains` rather than assumed to match upstream's
timing:

- `experimental.componentDetection`: `Soon` → **`2.12+`**, not their `4.11+` —
  `530b9616` (#396) is in no tag before `v2.12.0`
- `input-rating.md`: `New` dropped — `d08b5830` (#283) shipped in `v2.10.0`, two
  releases back, so the badge was stale here too
- `splitter.md`, `progress-group.md`: badge **added**, not edited — both first
  appear in `v2.12.0` and our pages never carried one
- the `::note` badges upstream removes were never added here: `07f3fe8d` ported
  those notes without them, precisely because this commit deletes them

Left alone: `calendar.md`, `drawer.md`, `modal.md`, `slideover.md` and the two
`With external scroll element` badges — this fork's own markers on sections
upstream's commit does not mention.

Verified by mutation, not by a passing suite. Upstream's 14 `aria` cases and 2
render cases are ported; with `Range.vue` reverted and the tests kept, **11 of
the 14 fail** plus all 3 affected render cases. The 3 that pass either way pin
behaviour that was already right — the `'Thumb'` fallback, not grouping an
unlabelled range, leaving non-`aria` attributes on the root — and are kept as
regression pins rather than counted as evidence.

Badges checked in the built navigation data: `splitter` and `progress-group`
carry `New`, `input-rating` no longer does, `scroll-area` is untouched, and
`2.12+` renders on the Vue installation page.

Gate with `CI=true`: `dev:prepare` · `lint` · `typecheck` · `test` (7016 passed,
6 skipped, 308 files) · `build` · `docs:generate`.

Ledger: cursor → `aa5f4af0` (upstream HEAD), three entries, parity snapshot
refreshed (one line, zero package differences).
@IgorShevchik
IgorShevchik merged commit 4e42a22 into main Aug 22, 2026
1 check passed
@IgorShevchik
IgorShevchik deleted the sync/nuxt-d6c3802a branch August 22, 2026 10:00
IgorShevchik added a commit that referenced this pull request Aug 22, 2026
`d6c3802a`, `f62aa143` and `aa5f4af0` now point at #466 and its squash SHA
`4e42a221`. `07f3fe8d` is reconciled here too, with #464 and `a2d9083d`.

That last one is a process slip worth recording: §6 step 4 has each port
reconcile the **previous** entry, so #466 should have closed out `07f3fe8d`
while it was closing out its own run. It did not, and nothing failed — the
ledger simply carried a `pending-merge` on a commit that had shipped two hours
earlier. Caught by re-reading the file rather than by a gate; the check is one
line and now runs as part of this step.

No entry is left unreconciled, and the cursor `aa5f4af0` is upstream HEAD.

Bookkeeping only — no source, test or docs change.

Co-authored-by: Shevchik Igor <noreply@anthropic.com>
IgorShevchik pushed a commit that referenced this pull request Aug 23, 2026
Only the subject reaches `CHANGELOG.md` — the body is not rendered, breaking
notes aside — so it is the one place a reader of the release notes can be
handed a way back to what was actually ported. Without it a port is
indistinguishable from local work in the only artefact most consumers read.

The subject stays ours. Copying upstream's own first line was the request as
originally put, and it is not what this does: their `Slider` is this fork's
`Range`, and §1 of PORTING.md makes that class of rename mandatory, so their
wording would put a component this library does not ship into our changelog.
The reference points at the commit; the sentence describes what changed here.

    fix(Range): forward aria attributes to the thumb (nuxt/ui@d6c3802)

The trigger is a **new key in `processed`**, not the ledger being edited. That
distinction is the whole design: a reconciliation commit — §6 step 4 requires
one whenever a run's last entry has no follower — touches the same file and
ports nothing, and demanding a reference there would be wrong. Checked against
real history rather than fixtures: #467 (bookkeeping) passes, #470 (local work)
passes, #466 and #464 (real ports) are flagged.

Two mistakes worth recording, both of the shape this repository keeps hitting.
The first draft returned an empty array and tested it for truthiness, so every
commit was reported as an unnamed port; running it once was enough. The second
was quieter: without `HEAD^` the check returns nothing and passed silently, and
`actions/checkout` defaults to depth 1 — the same fail-open as the PyYAML
fallback removed in #468. It now warns when it cannot see the previous
revision, and ci.yml fetches depth 2.

`--stdin` skips it: a bare title cannot say what a commit touches, so the
PR-title job checks the parse and the type only. Mutation testing caught that
the case asserting this was vacuous — run from the repository root it passed
whether the guard respected `--stdin` or not, because HEAD there ports nothing.
It now stands on a port revision where the HEAD path does fire.

Refs #437

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
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