Component

A composable scrollable container with custom-styled scrollbars. Built from sub-components so you have full control over layout and appearance.

View component changelog
preview
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Item 21
Item 22
Item 23
Item 24
Item 25
Item 26
Item 27
Item 28
Item 29
Item 30
Item 31
Item 32
Item 33
Item 34
Item 35
Item 36
Item 37
Item 38
Item 39
Item 40
Item 41
Item 42
Item 43
Item 44
Item 45
Item 46
Item 47
Item 48
Item 49
Item 50
React
"use client" import ScrollArea from "@radui/ui/ScrollArea" const TAGS = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`) const ScrollAreaExample = () => { return ( <ScrollArea.Root customRootClass="rad-ui" style={{ height: 200, width: 260, border: '1px solid #e5e7eb', borderRadius: 8 }}> <ScrollArea.Viewport style={{ padding: '8px 12px' }}> {TAGS.map(tag => ( <div key={tag} style={{ padding: '4px 0', fontSize: 14 }}>{tag}</div> ))} </ScrollArea.Viewport> <ScrollArea.Scrollbar orientation="vertical"> <ScrollArea.Thumb /> </ScrollArea.Scrollbar> <ScrollArea.Corner /> </ScrollArea.Root> ) } export default ScrollAreaExample

Use scrollRestoration="manual" when ScrollArea is the page-level scroller and the viewport should reset after navigation. Keep the default auto behavior for nested scroll regions, code blocks, chat panes, virtualized lists, and other areas that should preserve their current scroll offset across rerenders. Pass a stable restoreKey, such as the current pathname, to choose when the reset happens.

React
import { usePathname } from 'next/navigation'; import ScrollArea from '@radui/ui/ScrollArea'; export function PageScroller({ children }) { const pathname = usePathname(); return ( <ScrollArea.Root customRootClass="rad-ui" scrollRestoration="manual" restoreKey={pathname} style={{ height: '100%', width: '100%' }} > <ScrollArea.Viewport style={{ height: '100%' }}> {children} </ScrollArea.Viewport> <ScrollArea.Scrollbar orientation="vertical"> <ScrollArea.Thumb /> </ScrollArea.Scrollbar> </ScrollArea.Root> ); }

Import all parts of the component and piece them together

React
import ScrollArea from "@radui/ui/ScrollArea" export default () => { return ( <ScrollArea.Root customRootClass="rad-ui"> <ScrollArea.Viewport /> <ScrollArea.Scrollbar orientation="vertical"> <ScrollArea.Thumb /> </ScrollArea.Scrollbar> <ScrollArea.Scrollbar orientation="horizontal"> <ScrollArea.Thumb /> </ScrollArea.Scrollbar> <ScrollArea.Corner /> </ScrollArea.Root> ) }

The root ScrollArea container.

PropTypeDefault
type
enum
hover
scrollRestoration
enum
auto
restoreKey
React.Key
undefined
customRootClass
string
""
asChild
boolean
false

The scrollbar track element.

PropTypeDefault
orientation
enum
vertical
className
string
""
asChild
boolean
false
ShortcutDescription
Tab

Moves focus into and out of focusable content inside the viewport.

ArrowUp

Scrolls vertically when focus is inside the viewport and the focused element does not handle the key.

ArrowDown

Scrolls vertically when focus is inside the viewport and the focused element does not handle the key.

ArrowLeft

Scrolls horizontally when focus is inside the viewport and the focused element does not handle the key.

ArrowRight

Scrolls horizontally when focus is inside the viewport and the focused element does not handle the key.

PageUp

Scrolls toward the start of the vertical viewport by a larger step.

PageDown

Scrolls toward the end of the vertical viewport by a larger step.

Home

Moves to the start of focused scrollable content when the browser provides native scroll handling.

End

Moves to the end of focused scrollable content when the browser provides native scroll handling.

ReferenceWhat Rad UI follows

ScrollArea does not add a widget role by default. Add role="region" with an accessible name only when the scrollable content should be exposed as a navigable landmark.