09:12
Design review scheduled
Maya added the component audit to Thursday's agenda.
A React scroll area with native scrolling, Liquid Glass scrollbars, and a glass panel.
ScrollArea renders the glass panel, native scroll viewport, content container, and custom scrollbars internally.
Native scrollbars are hidden. The themed scrollbars stay subtle at rest and brighten while the pointer is over the area or the viewport is scrolling. They only render when the content actually overflows.
ScrollArea has no intrinsic height. Give the root a height with className to create a scrollable viewport. The example below also passes aria-label, which is forwarded to the scrollable viewport instead of the presentation root.
Set orientation="horizontal" to render only the horizontal scrollbar. Content wider than the viewport can still be scrolled with a trackpad, wheel, or keyboard.
Use orientation="both" for two-dimensional content. The corner is rendered so the two scrollbars never overlap.
The root owns the glass surface. Use className for its width, height, radius, and outer layout. Padding belongs inside the content, as the examples do, so list rows can also run edge to edge when needed.
overflowEdgeThreshold controls how close the viewport must be to an edge before the data-overflow-* attributes change. The example reacts after 16px of scrolling.
The ring appears once the viewport scrolls 16px past the top edge.
The viewport is focusable only while it can scroll, matching native scroll-container behavior. Pass aria-label or aria-labelledby to name the region, and aria-describedby for extra instructions.
Pointer and keyboard scrolling stay native, while the custom scrollbars remain decorative and hidden from assistive technology. See the accessibility guide for region naming.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Scrollable content rendered inside the viewport. |
orientation | "vertical" | "horizontal" | "both" | "vertical" | Scrollbar axes to render. |
overflowEdgeThreshold | number | Partial<{ xStart: number; xEnd: number; yStart: number; yEnd: number }> | 0 | Distance in pixels before an edge is marked as overflowing. |
aria-label | string | — | Accessible name forwarded to the scrollable viewport. |
aria-labelledby | string | — | ID of an element that labels the viewport. |
aria-describedby | string | — | ID of an element that describes the viewport. |
render | ReactElement | ((props, state) => ReactElement) | — | Replaces the root element. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the root element. |
className | string | — | Tailwind classes merged into the root. Set the height here. |
style | CSSProperties | — | Inline styles merged into the same element as className. |
ui | { root?: ClassValue; glass?: ClassValue; overlay?: ClassValue; viewport?: ClassValue; content?: ClassValue; scrollbar?: ClassValue; thumb?: ClassValue; corner?: ClassValue } | — | Tailwind classes for internal slots, keyed by data-slot. |
| Attribute | Description |
|---|---|
data-orientation | Indicates the enabled scrollbar axes (horizontal, vertical, or both). |
data-scrolling | Present while the user scrolls inside the area. |
data-has-overflow-x | Present when content is wider than the viewport. |
data-has-overflow-y | Present when content is taller than the viewport. |
data-overflow-x-start | Present when there is horizontal overflow on the start side. |
data-overflow-x-end | Present when there is horizontal overflow on the end side. |
data-overflow-y-start | Present when there is vertical overflow on the start side. |
data-overflow-y-end | Present when there is vertical overflow on the end side. |
data-hovering | Present on a scrollbar while the pointer is over the area. |
data-slot | Marks internal parts (root, glass, overlay, viewport, content, scrollbar, thumb, corner) for styling. |
The component uses the shared glass material. Tune shared --ui-glass-* tokens on a parent, use className for layout, and use ui for internal slots keyed by data-slot. Component-specific values live in src/theme/scroll-area.ts. See the theming guide for token layers and presets.