Usage
import { ScrollArea } from "@voila.dev/ui/scroll-area";<ScrollArea.Root className="h-56 w-72 rounded-lg border">…</ScrollArea.Root>For a bounded region inside the page — a list in a panel, a long menu, a code block — where the platform scrollbar would look out of place next to the surface it sits on. Do not wrap the page in one: the document should scroll with the browser's own scrollbar, which is what mobile chrome, scroll restoration and find-in-page are built around.
The height has to come from you. ScrollArea.Root is position: relative and
nothing more, so a root with no bound simply grows and never scrolls. Bound it
with a utility class, or with flex-1 min-h-0 inside a flex column.
ScrollArea.Root renders the viewport and a vertical bar for you — the
children you pass go inside the viewport, not next to it.
Recipes
A composed horizontal bar
Horizontal scrolling needs its bar composed in, since the root only ships the
vertical one: render <ScrollArea.Bar orientation="horizontal" /> alongside the
content and give the content a width the container cannot fit (w-max on a
flex row is the usual trick).
keepMounted on a bar renders it whether or not the pointer is near, which is
mostly useful in tests and screenshots; the default fade is the better default
for a real surface.
API
ScrollArea.Root
| Prop | Type | Default | |
|---|---|---|---|
className | string | ((state: ScrollAreaRootState) => string | undefined) | — | CSS class applied to the element, or a function that returns a class based on the component's state. |
overflowEdgeThreshold | number | Partial<{ xStart: number; xEnd: number; yStart: number; yEnd: number; }> | — | The threshold in pixels that must be passed before the overflow edge attributes are applied. Accepts a single number for all edges or an object to configure them individually. |
render | ComponentRenderFn<HTMLProps, ScrollAreaRootState> | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Allows you to replace the component's HTML element
with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
style | CSSProperties | ((state: ScrollAreaRootState) => CSSProperties | undefined) | — | Style applied to the element, or a function that returns a style object based on the component's state. |
Plus the DOM props of the element it renders. Source: scroll-area/components/scroll-area-root.tsx.
ScrollArea.Bar
| Prop | Type | Default | |
|---|---|---|---|
className | string | ((state: ScrollAreaScrollbarState) => string | undefined) | — | CSS class applied to the element, or a function that returns a class based on the component's state. |
keepMounted | boolean | — | Whether to keep the HTML element in the DOM when the viewport isn't scrollable. |
orientation | "horizontal" | "vertical" | "vertical" | Whether the scrollbar controls vertical or horizontal scroll. |
render | ComponentRenderFn<HTMLProps, ScrollAreaScrollbarState> | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Allows you to replace the component's HTML element
with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
style | CSSProperties | ((state: ScrollAreaScrollbarState) => CSSProperties | undefined) | — | Style applied to the element, or a function that returns a style object based on the component's state. |
Plus the DOM props of the element it renders. Source: scroll-area/components/scroll-area-bar.tsx.
Both parts wrap Base UI's Scroll Area,
which owns overflowEdgeThreshold, keepMounted and the state-function form of
className and style.