1
ComponentsLayout

Scroll Area

Bounded overflow regions with keyboard scrolling, overlay scrollbars and optional edge fades.

Purpose

Use Scroll Area when content must overflow a deliberately bounded region while retaining Siteplane overlay scrollbars and keyboard scrolling.

Basic usage

import { ScrollArea } from "@/components/ui/scroll-area";

export function Example() {
  return (
    <ScrollArea className="h-40">
      <div>Scrollable content</div>
    </ScrollArea>
  );
}

Installation

With the Siteplane registry alias configured, add the component and import the installed source from your app.

CLI

pnpm dlx shadcn@4.16.1 add @siteplane/scroll-area

Import

import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";

Need the machine-readable source metadata? View registry JSON.

Usage

Scroll Area gives constrained content a styled scrollbar and optional scroll fade. The root needs a height or width constraint from its parent, and it mounts both scrollbars and the corner internally.

import { ScrollArea } from "@/components/ui/scroll-area";

export function Example() {
  return (
    <ScrollArea className="h-40">
      <div>Scrollable content</div>
    </ScrollArea>
  );
}

Examples

Horizontal rows, both axes, the scrollbar gutter and fixed-chrome bodies are props and compositions of the same primitive.

Horizontal

A w-max row forces overflow; the horizontal scrollbar comes from the primitive.

<div className="overflow-hidden rounded-lg border">
  <ScrollArea aria-label="Horizontal scroll example">
    <div className="flex w-max gap-2 p-3">
      {items.map((item) => (
        <div className="size-16 shrink-0 rounded-md border" key={item}>
          {item}
        </div>
      ))}
    </div>
  </ScrollArea>
</div>

Both axes

Content wider and taller than the box scrolls on both axes; the corner is handled internally.

<div className="h-48 overflow-hidden rounded-lg border">
  <ScrollArea aria-label="Both axes scroll example">
    <div className="grid w-max gap-2 p-3">
      {rows.map((row) => (
        <div className="flex gap-2" key={row.id}>
          {row.cells.map((cell) => (
            <div className="size-12 shrink-0 rounded-md border" key={cell}>
              {cell}
            </div>
          ))}
        </div>
      ))}
    </div>
  </ScrollArea>
</div>

Scrollbar gutter

scrollbarGutter reserves edge padding only while the axis overflows, so rows never sit under the scrollbar.

<div className="h-40 overflow-hidden rounded-lg border">
  <ScrollArea aria-label="Scrollbar gutter example" scrollbarGutter>
    <ul className="grid gap-2 p-3 text-sm">
      {rows.map((row) => (
        <li key={row}>{row}</li>
      ))}
    </ul>
  </ScrollArea>
</div>

Card scroll body

Header and footer stay fixed; only the body scrolls inside its height constraint.

Release notes
6 updates
<div className="grid overflow-hidden rounded-lg border">
  <div className="border-b px-3 py-2">
    <span className="font-medium text-sm" id={labelId}>Release notes</span>
  </div>
  <div className="h-32">
    <ScrollArea aria-labelledby={labelId}>
      <div className="grid gap-2 p-3 text-sm">{notes}</div>
    </ScrollArea>
  </div>
  <div className="border-t px-3 py-2 text-xs">6 updates</div>
</div>

API Reference

The reference lists the source-owned exports and props that are easy to miss in visual examples. Inherited Base UI props remain available unless the wrapper narrows them.

  • ScrollArea accepts scrollFade, scrollbarGutter, fill and clampContentMinWidth in addition to the Base UI root props.
  • fill makes the content fill the viewport, which is useful for full-height children and centered empty states.
  • clampContentMinWidth defaults to true; set it to false when intrinsic-width content should create horizontal scrolling instead of shrinking.
  • ScrollBar is exported for custom composition and accepts orientation="vertical" | "horizontal".

Motion

Component motion uses the shared Siteplane motion contract. See the global motion guide for provider setup, tokens and reduced-motion behavior.

  • Scrollbars fade through the native Siteplane Scroll Area transition. Content itself does not animate as it scrolls.
  • The operating-system reduced-motion preference removes the scrollbar fade and its delay. The forced reducedMotionPreset sets the active fade duration to 0ms while keeping scrolling and the scrollbar usable.

Accessibility

  • Give the region an accessible name and a real bounded height or width.
  • Preserve the focusable viewport and visible focus ring for keyboard scrolling.
  • Do not hide required actions beyond an undiscoverable scroll boundary, and use pagination for very large datasets.

Implementation Guidance

  • Avoid nested scroll areas on the same axis.
  • Choose clampContentMinWidth={false} for wide tables or rows that must retain intrinsic width.
  • Do not replace large-data pagination with one indefinitely growing Scroll Area.

On This Page