Scroll area
A scroll container with a slim themed scrollbar that stays out of the way until you hover or scroll.
npx prodular-ui add scroll-areaVertical
A fixed height panel with a long list.
import { ScrollArea } from "@/components/ui/scroll-area"
const events = [ ["invoice.paid", "Pinecrest Health paid INV-2048", "09:42"], ["customer.updated", "Corvid Labs changed the billing email", "09:31"], ["subscription.renewed", "Halden Analytics renewed the Team plan", "09:12"], ["invoice.payment_failed", "Charge to Marlow and Finch was declined", "08:57"], ["seat.added", "Tidewater Freight added 4 seats", "08:40"], ["invoice.created", "Draft INV-2049 created for Juniper Studio", "08:22"], ["webhook.failed", "hooks.tidewater.co returned 503", "08:05"], ["api_key.rotated", "Maya Okafor rotated the production key", "07:48"], ["invoice.paid", "Orbit Studio paid INV-2043", "07:30"], ["customer.created", "Kestrel Bank signed up on the Starter plan", "07:11"], ["coupon.applied", "LAUNCH20 applied to Kestrel Bank", "07:11"], ["export.completed", "Nightly usage export finished in 4m 12s", "03:04"],]
export default function ScrollAreaVertical() { return ( <ScrollArea className="h-72 w-full max-w-md rounded-xl border bg-card shadow-xs"> <div className="px-4 py-3"> <h4 className="pb-2 text-sm font-medium">Events today</h4> <ul className="divide-y"> {events.map(([type, text, time]) => ( <li key={type + time} className="flex items-baseline gap-3 py-2.5"> <div className="flex min-w-0 flex-col gap-0.5"> <span className="truncate text-sm">{text}</span> <span className="font-mono text-xs text-muted-foreground">{type}</span> </div> <span className="ml-auto text-[13px] text-muted-foreground tabular-nums">{time}</span> </li> ))} </ul> </div> </ScrollArea> )}Horizontal
Add ScrollBar orientation="horizontal" and give the content w-max.
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
const releases = [ { version: "v2.18.0", date: "Oct 20", title: "Usage based pricing tiers" }, { version: "v2.17.2", date: "Oct 14", title: "Faster invoice PDF rendering" }, { version: "v2.17.0", date: "Oct 07", title: "Dunning emails in 9 languages" }, { version: "v2.16.1", date: "Sep 30", title: "Webhook retry dashboard" }, { version: "v2.16.0", date: "Sep 23", title: "Tax IDs for EU customers" }, { version: "v2.15.0", date: "Sep 12", title: "Bulk credit notes" },]
export default function ScrollAreaHorizontal() { return ( <ScrollArea className="w-full max-w-lg"> <ol className="flex w-max divide-x pb-4"> {releases.map((r) => ( <li key={r.version} className="flex w-48 flex-col gap-1 px-4 first:pl-0"> <span className="text-[13px] text-muted-foreground tabular-nums"> {r.version} · {r.date} </span> <span className="text-sm font-medium">{r.title}</span> </li> ))} </ol> <ScrollBar orientation="horizontal" /> </ScrollArea> )}Anatomy
<ScrollArea className="h-72"> <div className="p-4">...</div></ScrollArea>Guidance
Use it when
- Fixed height regions inside a layout: a side panel, a popover list, a log.
- Horizontal rows of items that do not wrap.
Avoid
- The whole page. Let the document scroll natively.
- Nested scroll areas in the same direction.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Give ScrollArea a fixed height (h-72) or max height for vertical scrolling. Without it nothing scrolls.
- For horizontal scrolling, add <ScrollBar orientation="horizontal" /> as a child and make the content w-max.
- Put padding on the content inside the ScrollArea, not on the ScrollArea itself, so the scrollbar sits at the edge.
- The viewport is focusable for keyboard scrolling. Do not remove its focus ring.
API
ScrollArea
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | Size of the scroll region, for example h-72. |
ScrollBar
| Prop | Type | Default | Description |
|---|---|---|---|
| orientation | "vertical" | "horizontal" | "vertical" | Which scrollbar to render. The vertical one is included by default. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add scroll-area# or, with the registry in components.jsonnpx shadcn@latest add @prodular/scroll-area