v0.5

Scroll Area

Styled scroll container with overlay scrollbars for vertical, horizontal, or both axes.

Tags

v1.2.0-beta.50
v1.2.0-beta.49
v1.2.0-beta.48
v1.2.0-beta.47
v1.2.0-beta.46
v1.2.0-beta.45
v1.2.0-beta.44
v1.2.0-beta.43
v1.2.0-beta.42
v1.2.0-beta.41
v1.2.0-beta.40
v1.2.0-beta.39
v1.2.0-beta.38
v1.2.0-beta.37
v1.2.0-beta.36
v1.2.0-beta.35
v1.2.0-beta.34
v1.2.0-beta.33
v1.2.0-beta.32
v1.2.0-beta.31
v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1

Description

ScrollArea is a styled wrapper around Radix's ScrollArea primitive. It renders a viewport plus overlay scrollbars that match the design system, so a scrolling region inside a card, panel, or popover doesn't fall back to the browser's native scrollbar.

Reach for it when content needs to scroll inside a fixed-size surface: long tag lists in a sidebar, image rows in a gallery card, release matrices, dropdown menus that overflow, code blocks, anywhere the native scrollbar would clash with the surrounding chrome. From the consumer's perspective it's a single element. The viewport, track, and thumb are all rendered for you.

Don't use ScrollArea for full-page scrolling. The browser handles that more efficiently and accessibly than any JS-driven solution. Skip it for short content that already fits its container (a scrollbar that never appears is just dead weight). For tabular data prefer the table's own overflow behavior; ScrollArea is for free-form content.

Installation

pnpm dlx @create-ui/cli add scroll-area

Usage

import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="h-72 w-48">{children}</ScrollArea>

Examples

Vertical

The default orientation. Set a fixed height (and width if needed) on the root via className; the viewport scrolls vertically as soon as its content exceeds that height.

Tags

v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1

Horizontal

Pass orientation="horizontal" for a single-axis horizontal scroller. The track flips to the bottom edge and the content row scrolls left/right.

Photo by Ornella Binni
Photo by Ornella Binni
Photo by Tom Byrom
Photo by Tom Byrom
Photo by Vladimir Malyav
Photo by Vladimir Malyav

Both Axes

orientation="both" enables both scrollbars at once. Useful for wide grids, large diagrams, or tables that exceed the surface in both dimensions.

Release matrix

v1.0.0
v1.0.1
v1.0.2
v1.0.3
v1.0.4
v1.0.5
v1.1.0
v1.1.1
v1.1.2
v1.1.3
v1.1.4
v1.1.5
v1.2.0
v1.2.1
v1.2.2
v1.2.3
v1.2.4
v1.2.5
v1.3.0
v1.3.1
v1.3.2
v1.3.3
v1.3.4
v1.3.5
v1.4.0
v1.4.1
v1.4.2
v1.4.3
v1.4.4
v1.4.5
v1.5.0
v1.5.1
v1.5.2
v1.5.3
v1.5.4
v1.5.5
v1.6.0
v1.6.1
v1.6.2
v1.6.3
v1.6.4
v1.6.5
v1.7.0
v1.7.1
v1.7.2
v1.7.3
v1.7.4
v1.7.5
v1.8.0
v1.8.1
v1.8.2
v1.8.3
v1.8.4
v1.8.5
v1.9.0
v1.9.1
v1.9.2
v1.9.3
v1.9.4
v1.9.5

Fade

Enable fade to render a gradient overlay at the scroll-end of each enabled axis. The overlay fades out once the viewport reaches the end of the content, signalling "there's more below / to the right" without adding a hard divider.

Tags

v1.2.0-beta.30
v1.2.0-beta.29
v1.2.0-beta.28
v1.2.0-beta.27
v1.2.0-beta.26
v1.2.0-beta.25
v1.2.0-beta.24
v1.2.0-beta.23
v1.2.0-beta.22
v1.2.0-beta.21
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1

Sizes

size controls scrollbar thickness. sm is unobtrusive for dense surfaces, md (default) is the everyday choice, lg is meant for touch targets or content-heavy panels where the bar doubles as a hint.

v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
sm
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
md
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
lg

Appearance

appearance swaps the track styling. filled (default) adds a bg-weak track so the scrollbar reads as a distinct surface; ghost removes the track entirely and leaves only the thumb, useful inside already-tinted surfaces.

v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
filled
v1.2.0-beta.20
v1.2.0-beta.19
v1.2.0-beta.18
v1.2.0-beta.17
v1.2.0-beta.16
v1.2.0-beta.15
v1.2.0-beta.14
v1.2.0-beta.13
v1.2.0-beta.12
v1.2.0-beta.11
v1.2.0-beta.10
v1.2.0-beta.9
v1.2.0-beta.8
v1.2.0-beta.7
v1.2.0-beta.6
v1.2.0-beta.5
v1.2.0-beta.4
v1.2.0-beta.3
v1.2.0-beta.2
v1.2.0-beta.1
ghost

Accessibility

The viewport is keyboard-scrollable once focused. Radix exposes the viewport with tabIndex={0} so it lands in the tab order, which means screen-reader and keyboard-only users can scroll without a pointer.

KeyDescription
TabMoves focus into the viewport.
Arrow keysScroll the viewport by a small step.
PageUp / PageDownScroll the viewport by one page.
Home / EndJump to the start / end of the scroll axis.

ARIA notes:

  • The scrollbars and thumb are decorative and marked aria-hidden. They expose no role, since pointer drag is the only thing they're meant for.
  • Give the ScrollArea an accessible name (aria-label or aria-labelledby) when it's the primary content of a section so the focus stop announces meaningfully.
  • For long content regions, consider rendering a heading inside the viewport (<h2>, <h3>, etc.) so the structure is reachable by landmark navigation.
  • Built on Radix Scroll Area; see Radix's docs for the underlying primitive's behavior and props.

Styling

Tailwind override: pass className to set sizing and surface styles on the root. Width and height live on the root, not the viewport.

<ScrollArea className="bg-weakest h-72 w-48 rounded-md">{children}</ScrollArea>

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="scroll-area" on the root element.
  • data-slot="scroll-area-viewport" on the inner viewport that wraps children.
  • data-slot="scroll-area-scrollbar" on each scrollbar track, with data-orientation="vertical | horizontal".
  • data-slot="scroll-area-thumb" on the draggable thumb.
  • data-slot="scroll-area-fade" on each fade overlay, with data-orientation and data-state="visible | hidden".

Target a specific slot in CSS:

[data-slot="scroll-area-thumb"] {
  /* … */
}
  • Separator: divider lines between rows inside a scrolled list.
  • Table: use the table's own overflow for tabular data; ScrollArea is for free-form content.
  • Tooltip / Popover: when the overflow is a small floating panel, the popover primitive already handles its own scroll surface.

API Reference

ScrollArea

Wraps Radix's ScrollArea.Root and renders a viewport plus styled scrollbars. Accepts every prop the Radix root accepts (type, scrollHideDelay, dir, etc.). ScrollBar is exported separately for advanced layouts that need to render a scrollbar in a custom position.

Props

PropTypeDefaultDescription
orientation"vertical" | "horizontal" | "both""vertical"Which axes render a scrollbar.
fadebooleanfalseRenders a gradient overlay at the scroll-end of each enabled axis. Hides automatically when reached.
type"auto" | "always" | "scroll" | "hover""hover"Scrollbar visibility behavior, forwarded to Radix. (advanced)
scrollHideDelaynumber600Milliseconds before scrollbars hide when type="scroll" or "hover". (advanced)
dir"ltr" | "rtl"inheritsReading direction, forwarded to Radix. (advanced)
classNamestring-Tailwind classes merged onto the root via cn(). Width/height live here.
childrenReact.ReactNode-Content rendered inside the viewport.

Variants

VariantOptionsDefaultDescription
size"sm" "md" "lg""md"Scrollbar thickness.
appearance"filled" "ghost""filled"Track styling. filled adds a bg-weak track, ghost shows the thumb only.