P-08 · Primitives · Primitives
All elements · ScrollArea on the Primitives page
Last checked 2026-10-22 · Awaiting approval · Accessibility tests
Approve ScrollArea
Approving as
A scroll container whose edge shadows appear only when there is more content in that direction. Pure
CSS: the shadows are background layers with background-attachment: local, so no scroll
listener is needed. Replaces ScrollShadows.
| Axis | Values |
|---|---|
data-axis |
y (default) · x |
data-hide-scrollbar |
hide the bar, keep the shadows |
-
Row 1
-
Row 2
-
Row 3
-
Row 4
-
Row 5
-
Row 6
-
Row 7
-
Row 8
Guidance
When to use
- Scroll a list, pane or panel body inside a fixed-height region with edge shadows that show more content.
- Scroll a row of chips or filters sideways with
data-axis="x". - Host a long list that a VirtualScroller windows.
-
Contain scrolling in a pane so the page behind it does not scroll (
overscroll-behavior: contain).
When to consider something else
- When a long result set needs pages and a count, use Pagination instead of an endless scroll. See Pagination.
- When a toolbar runs out of width, use Overflow to move actions into a menu rather than scrolling them. See Overflow.
- When the region only needs layout and no scrolling, use Box. See Box.
- When very long homogeneous lists render slowly, add the VirtualScroller behavior inside the ScrollArea. See Behavioral primitives.
Usability
-
Give the scroll area a bounded height from its parent;
min-height: 0lets it shrink inside flex layouts. -
Keep the scrollbar visible for vertical lists; use
data-hide-scrollbaronly for short horizontal rows where shadows signal more. - Keep one scroll container per pane.
- Keep sticky headers inside the same scroll area as their rows.
- Don't nest scroll areas on the same axis.
- Don't hide the scrollbar on a long list; the shadows show there is more, not how much.
- Don't scroll the whole page sideways to fit wide content.
Accessibility
Keyboard
| Keys | Action |
|---|---|
| Tab |
Moves focus to the scroll area when it has tabindex="0" and no focusable content of
its own.
|
| Arrow Down / Arrow Up | Scrolls a focused vertical area (browser default). |
| Arrow Left / Arrow Right | Scrolls a focused horizontal area (browser default). |
| Page Down / Page Up, Home / End | Scrolls by a page or to the start or end (browser default). |
Roles and names
-
A focusable scroll area uses
role="region"with anaria-label, as the specimens do ("Rows", "Document types"). - When the content inside is a list, grid or listbox, the scroll area does not replace that content's own role.
Focus
-
Add
tabindex="0"when the content has no focusable children, so keyboard users can scroll it (2.1.1). - The focused scroll area shows the global
--qf-focus-ring(2.4.7). - When focus moves to an item inside, the browser scrolls it into view; it must not land under a sticky header (2.4.11).
Other requirements
- Edge shadows are CSS backgrounds with no scroll listener; they carry no meaning to assistive technology.
- Content must reflow at 320 CSS px without scrolling in two directions, except for data tables and similar content (1.4.10).
- Hidden scrollbars remove a visual cue; keep them for any list where position matters.
Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.
Accessibility tests
Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.
| Area | Automated | A person checks |
|---|---|---|
| General | Passed | Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme. |
| Zoom | Passed | At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping. |
| Keyboard | Passed | Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (4 rows) |
| Screen reader | Passed | With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (2 items) |
Approving. When the checklist passes on the checked run, record it with
bun run a11y:approve -- scrollarea --by "Your name" and commit
a11y/approvals.json with the rebuilt pages.
All test status
Package
Consumers link one stylesheet, css/classic/index.css, which includes every element. The
files below are where this element is defined.
Latest updates
No recorded changes yet.