Stable in React
Scroll Area
A native scroll container with custom scrollbars.
Install#
One package per framework. Scroll Area's parts come from it; the anatomy tab at the top shows how they nest.
bun add @▢▢▢▢/reactSix parts. The example uses five of them; the data does not say which are required.
ScrollArea.RootGroups all parts of the scroll area.ScrollArea.ViewportThe actual scrollable container of the scroll area.ScrollArea.ContentA container for the content of the scroll area.ScrollArea.ScrollbarA vertical or horizontal scrollbar for the scroll area.ScrollArea.ThumbThe draggable part of the scrollbar that indicates the current scroll position.ScrollArea.CornerA small rectangular area that appears at the intersection of horizontal and vertical scrollbars. Not in the example.
Examples#
Common ways to put it to work. Each one runs live.
Two scrollbars, with Corner where they meet.
ScrollAreaBoth.tsxStyling and accessibility#
The parts ship no styles. Style their states with these attributes; the CSS tab at the top has a sheet. The same CSS works in all five frameworks.
[data-scrolling]Present when the user scrolls inside the scroll area. On Root, Viewport, Content, Scrollbar, Thumb.[data-has-overflow-x]Present when the scroll area content is wider than the viewport. On Root, Viewport, Content, Scrollbar.[data-has-overflow-y]Present when the scroll area content is taller than the viewport. On Root, Viewport, Content, Scrollbar.[data-overflow-x-start]Present when there is overflow on the horizontal start side. On Root, Viewport, Content, Scrollbar.[data-overflow-x-end]Present when there is overflow on the horizontal end side. On Root, Viewport, Content, Scrollbar.[data-overflow-y-start]Present when there is overflow on the vertical start side. On Root, Viewport, Content, Scrollbar.[data-overflow-y-end]Present when there is overflow on the vertical end side. On Root, Viewport, Content, Scrollbar.--scroll-area-corner-heightThe scroll area's corner height. On Root.--scroll-area-corner-widthThe scroll area's corner width. On Root.--scroll-area-overflow-x-startThe distance from the horizontal start edge in pixels. On Viewport.--scroll-area-overflow-x-endThe distance from the horizontal end edge in pixels. On Viewport.--scroll-area-overflow-y-startThe distance from the vertical start edge in pixels. On Viewport.--scroll-area-overflow-y-endThe distance from the vertical end edge in pixels. On Viewport.[data-orientation]Indicates the orientation of the scrollbar. On Scrollbar, Thumb.[data-hovering]Present when the pointer is over the scroll area. On Scrollbar.--scroll-area-thumb-heightThe scroll area thumb's height. On Scrollbar.--scroll-area-thumb-widthThe scroll area thumb's width. On Scrollbar.
Keyboard
ScrollArea adds no keys: Viewport takes focus when its content overflows, and the browser scrolls it with the arrow keys, PageUp, PageDown, Home and End.
Set for you
keyboard users can focus the region and scroll itViewporttabindex="0"while the content overflowskeeps its own rolethe scrollable region is not hidden from assistive technologyViewportthe custom bars are not read; the native scroll position isScrollbararia-hidden="true"the corner piece is not readCorneraria-hidden="true"the wrapper adds nothing to what is readRootrole="presentation"the inner wrapper adds nothing to what is readContentrole="presentation"
API reference#
3 props across 6 parts, in React syntax, and className, style, render once for every part. Open a row to try it.
ScrollArea · all partsclassNameCSS class applied to the element, or a function that
returns a class based on the component's state.string | ((state: State) => string | undefined)styleStyle applied to the element, or a function that
returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>Use it in React#
What differs from the React API. Switch the framework at the top of the page.
@▢▢▢▢/react is the React 19 package. Its parts, props, data attributes and error messages are upstream Base UI's, and upstream's own tests run against it.
- Parts
Each component is its own entry point and exports one namespace named after it.
import { Switch } from '@base-ui-next/react/switch' export function Example() { return ( <Switch.Root> <Switch.Thumb /> </Switch.Root> ) }A part renders the element its API reference names, such as a
<span>forSwitch.Root. - Props and events
Props and callbacks have upstream's names and signatures:
onCheckedChange(checked, details),onOpenChange(open, details),onValueChange(value, details).detailscarriesreason,event,cancel()andallowPropagation(). Native handlers are React's (onClick,onKeyDown), andevent.preventBaseUIHandler()stops a part's own handler. - Styling
classNametakes a string or a function(state) => string;styletakes an object or a function(state) => object. The state'sdata-*attributes are on the element for CSS. renderrendertakes an element (render={<a href="/docs" />}) or a function(props, state) => elementthat spreadspropson what it returns.- Refs
refreaches the part's element. Imperative handles are ref props, as upstream:inputRef, andactionsRef({ validate }on Field and Form,{ unmount, close }on Dialog). - Binding
A part is controlled when its value prop (
checked,open,value) is set, and uncontrolled with thedefaultform (defaultChecked,defaultOpen,defaultValue). React has no two-way binding: pair the value with its change callback. - From @base-ui/reactChange the import from
@base-ui/react/<component>to@▢▢▢▢/react/<component>. - From @base-ui/reactNothing else changes: props, parts, data attributes and errors are the same.