Skip to content

spec(AST-025): a Tab-able scroll area is named by its owner (FR12) - #9088

Merged
cixzhang merged 1 commit into
mainfrom
spec/ast-025-fr12-scroll-name
Oct 31, 2026
Merged

cixzhang merged 1 commit into
mainfrom
spec/ast-025-fr12-scroll-name

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

User impact

Keyboard and screen-reader users who Tab into a scrolling area now hear where they landed: "main" on a scrolling AppShell page, or "Featured products, group" in a carousel. Today FR12 requires a role and a name but never says where the name comes from, so a stop can be silent or repeat what its role already says.

Change

spec:AST-025 FR12 now says how the name is chosen:

  • The role is group unless the viewport is itself a landmark.
  • The name is the owning component's accessible name: the caller's label, else that component's translated default.
  • The page's only landmark of its role, such as the single main, MAY rely on that role and carry no name. One of several landmarks of its role MUST be named.

A new verification row covers an owner-named group, a single main relying on its role, and a second unnamed main failing.

Governs

Checks

pnpm check:knowledge and Prettier pass.

@vercel

vercel Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Error Error Oct 31, 2026 1:33am UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 31, 2026
@astracat-bot

astracat-bot Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🔄 In progress (for maintainers only) Oct 31, 2026, 1:34 AM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Oct 31, 2026
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec a0a464a

@cixzhang cixzhang closed this Oct 31, 2026
@cixzhang cixzhang reopened this Oct 31, 2026
@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Oct 31, 2026
@cixzhang
cixzhang merged commit c538317 into main Oct 31, 2026
92 of 93 checks passed
cixzhang pushed a commit that referenced this pull request Oct 31, 2026
…e it overflows (#8155)

## User impact

A keyboard user who tabs onto a Carousel's scroll area lands on an element with no role and no name, so a screen reader announces nothing. The same unnamed stop appears even when everything fits. The edge buttons hand focus here when their direction runs out (component:Carousel FR2).

## Evidence

Chromium, keys captioned: Tab rings the › button, a second Tab focuses the scroll area, → → → ← scroll it. Its ring is the browser's default outline.

![Chromium, keyboard only: Tab reaches the scroll area, the arrows scroll it](https://raw.githubusercontent.com/vjeux/astryx/136eab094dbb72fc2b8cdbeed5e447170c553ee6/carousel-scroll-area-keyboard.gif)

- Before: the binding's `scroller-keyboard` state failed `carousel.scroller.role-and-name`, recorded as a known failure. After: it passes 8/8 with no known failures, and axe reports 0 violations on every Carousel story.
- New unit tests fail without the change: the named group, the tab stop following overflow, and the tab stop following slides added, removed or grown with the box unchanged. Another pins the translated default name.
- In Chromium and WebKit, before the re-measure, a fixed-width carousel's tab stop went stale as its content changed, and Scroll right stayed disabled after a slide was added at the end; both follow now.

## Problem and solution fit

- The scroll area is `role="group"`, named like the carousel (the caller's `aria-label`, else the translated "Carousel"), so landing on it says where the user is.
- It is a tab stop (`tabIndex={0}`) only while its content overflows; while it fits it is `tabIndex={-1}`, which keeps the edge buttons' programmatic hand-off (FR2) working.
- The overflow is measured again when the content changes inside an unchanged box: `useScrollOverflow` now observes each child's box, children added or removed, and the container's class and style (`spec:AST-025` FR5). The edge buttons and fades, and TabList's fades, follow the same measure.

## Expected behavior and authority

`spec:AST-025` FR12: a viewport that takes keyboard scrolling joins the tab order only while it overflows, with a role and an accessible name; as #9088 states it, a `group` named by the component that owns it, the caller's label, else its translated default. `component:Carousel` FR2 names it the hand-off target, out of the tab order when the content fits.

## Smallest restoration

- Three attributes on the scroll area; `useScrollOverflow` also observes the content, with its API unchanged.
- `Carousel.doc.mjs` and the Carousel record's review table describe the new behavior; the binding's known failure is removed.
- Tab entry does not delegate to a first link or button (FR12's optional path); that needs #8111's shared delegation.

## Writing rubric results

R1 narration: a projection row called the gap pending; it now states the behavior. R2–R6: none.

## Scope

- [x] One defect is restored.
- [x] Separable contradictory or unsettled tagalongs were removed or split.
- [x] No new public API, visual representation, default, or interaction model is hidden under the bug-fix label.
- [x] Public text and artifacts contain no internal Meta context.

## Testing

Local gates at a2184a1:

- `pnpm exec vitest run packages/core/src/Carousel packages/core/src/hooks/useScrollOverflow.test.tsx packages/core/src/TabList`: 5 files, 158 tests passed.
- `pnpm exec playwright test packages/core/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts`: 8 passed.
- `pnpm a11y:audit -- --components core/Carousel`: 0 violations, gate passed.
- `pnpm test:ui`: 16,462 passed. The node project: 14,563 passed; its only failures are `packages/cli/foundation/release/cache.test.mjs` (fixed by #8520) and `apps/storybook/.storybook/story-tree.test.ts` (#8509), unrelated to this change.
- Root build and typecheck, `CI=true pnpm lint`, `pnpm check:knowledge`, `pnpm check:changesets` and its coverage, the Storybook build, the interaction config (136 passed), `pnpm check:repo`, Prettier: clean.
- Size: 10 files, 321 lines added, 43 removed.

Sibling: #7906 and #8153 also edit Carousel.tsx; whichever lands second rebases.
@github-actions
github-actions Bot deleted the spec/ast-025-fr12-scroll-name branch October 31, 2026 06:09

This branch had an error being deployed

1 failed deployment
Preview — a0a464a4 Deployed Oct 31, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant