ScrollArea

A scrollable region with a styled scrollbar.

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

PropTypeDefault
classNamestring | ((state: ScrollAreaRootState) => string | undefined)CSS class applied to the element, or a function that returns a class based on the component's state.
overflowEdgeThresholdnumber | 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.
renderComponentRenderFn<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.
styleCSSProperties | ((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

PropTypeDefault
classNamestring | ((state: ScrollAreaScrollbarState) => string | undefined)CSS class applied to the element, or a function that returns a class based on the component's state.
keepMountedbooleanWhether 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.
renderComponentRenderFn<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.
styleCSSProperties | ((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.

Resizable · List · Table