- Accordion
- Alert
- Alert Dialog
- Attachment
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Checkbox
- Collapsible
- Command
- Context Menu
- Data Table
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Pagination
- Popover
- Progress
- Questionnaire
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
Tags
import * as React from "react"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Separator } from "@/components/ui/separator"
const tags = Array.from({ length: 50 }).map(
(_, i, a) => `v1.2.0-beta.${a.length - i}`
)
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-72 w-48 rounded-lg border">
<div className="p-4">
<h4 className="mb-4 text-sm leading-none font-medium">Tags</h4>
{tags.map((tag) => (
<React.Fragment key={tag}>
<div className="text-sm tabular-nums">{tag}</div>
<Separator className="my-2" />
</React.Fragment>
))}
</div>
</ScrollArea>
)
}Installation#
pnpm dlx shadcn@latest add https://ui.ikramhasan.com/r/scroll-area.json
Usage#
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"<ScrollArea className="h-[200px] w-[350px] rounded-lg border p-4">
Your scrollable content here.
</ScrollArea>The scrollbar is a 6px thumb in a 10px track, in muted-foreground at 50% like the menus' scrollbars. It widens to 8px and darkens while you hover or drag it. The track sits inside the border, and its round ends clear corners up to rounded-lg. For a rounder container, inset the bar with className (e.g. data-vertical:py-2).
Composition#
Use the following composition to build a ScrollArea:
ScrollArea
└── ScrollBarExamples#
Horizontal#
Use ScrollBar with orientation="horizontal" for horizontal scrolling.
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
const swatches = [
{ name: "Dawn", from: "oklch(0.86 0.09 60)", to: "oklch(0.7 0.15 20)" },
{ name: "Lagoon", from: "oklch(0.88 0.08 190)", to: "oklch(0.6 0.12 230)" },
{ name: "Moss", from: "oklch(0.88 0.1 130)", to: "oklch(0.55 0.11 150)" },
{ name: "Dusk", from: "oklch(0.8 0.1 300)", to: "oklch(0.45 0.15 275)" },
{ name: "Ember", from: "oklch(0.9 0.12 90)", to: "oklch(0.62 0.19 40)" },
{ name: "Slate", from: "oklch(0.9 0.01 250)", to: "oklch(0.5 0.03 250)" },
]
export function ScrollAreaHorizontalDemo() {
return (
<ScrollArea className="w-96 rounded-lg border whitespace-nowrap">
<div className="flex w-max gap-4 p-4">
{swatches.map((swatch) => (
<figure key={swatch.name} className="shrink-0">
<div
className="aspect-[3/4] w-32 rounded-md outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10"
style={{
backgroundImage: `linear-gradient(to bottom, ${swatch.from}, ${swatch.to})`,
}}
/>
<figcaption className="pt-2 text-xs text-muted-foreground">
Gradient{" "}
<span className="font-medium text-foreground">{swatch.name}</span>
</figcaption>
</figure>
))}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
)
}Both directions#
ScrollArea always renders a vertical bar. Add a horizontal ScrollBar for content that overflows both ways.
12:04:00 INFO sync worker-1 processed batch 1200 (orders, customers, products) in 80ms 12:04:01 INFO sync worker-2 processed batch 1217 (orders, customers, products) in 117ms 12:04:02 INFO sync worker-3 processed batch 1234 (orders, customers, products) in 154ms 12:04:03 WARN sync worker-1 processed batch 1251 (orders, customers, products) in 191ms 12:04:04 INFO sync worker-2 processed batch 1268 (orders, customers, products) in 88ms 12:04:05 INFO sync worker-3 processed batch 1285 (orders, customers, products) in 125ms 12:04:06 INFO sync worker-1 processed batch 1302 (orders, customers, products) in 162ms 12:04:07 INFO sync worker-2 processed batch 1319 (orders, customers, products) in 199ms 12:04:08 INFO sync worker-3 processed batch 1336 (orders, customers, products) in 96ms 12:04:09 INFO sync worker-1 processed batch 1353 (orders, customers, products) in 133ms 12:04:10 WARN sync worker-2 processed batch 1370 (orders, customers, products) in 170ms 12:04:11 INFO sync worker-3 processed batch 1387 (orders, customers, products) in 207ms 12:04:12 INFO sync worker-1 processed batch 1404 (orders, customers, products) in 104ms 12:04:13 INFO sync worker-2 processed batch 1421 (orders, customers, products) in 141ms 12:04:14 INFO sync worker-3 processed batch 1438 (orders, customers, products) in 178ms 12:04:15 INFO sync worker-1 processed batch 1455 (orders, customers, products) in 215ms 12:04:16 INFO sync worker-2 processed batch 1472 (orders, customers, products) in 112ms 12:04:17 WARN sync worker-3 processed batch 1489 (orders, customers, products) in 149ms 12:04:18 INFO sync worker-1 processed batch 1506 (orders, customers, products) in 186ms 12:04:19 INFO sync worker-2 processed batch 1523 (orders, customers, products) in 83ms 12:04:20 INFO sync worker-3 processed batch 1540 (orders, customers, products) in 120ms 12:04:21 INFO sync worker-1 processed batch 1557 (orders, customers, products) in 157ms 12:04:22 INFO sync worker-2 processed batch 1574 (orders, customers, products) in 194ms 12:04:23 INFO sync worker-3 processed batch 1591 (orders, customers, products) in 91ms 12:04:24 WARN sync worker-1 processed batch 1608 (orders, customers, products) in 128ms 12:04:25 INFO sync worker-2 processed batch 1625 (orders, customers, products) in 165ms 12:04:26 INFO sync worker-3 processed batch 1642 (orders, customers, products) in 202ms 12:04:27 INFO sync worker-1 processed batch 1659 (orders, customers, products) in 99ms 12:04:28 INFO sync worker-2 processed batch 1676 (orders, customers, products) in 136ms 12:04:29 INFO sync worker-3 processed batch 1693 (orders, customers, products) in 173ms 12:04:30 INFO sync worker-1 processed batch 1710 (orders, customers, products) in 210ms 12:04:31 WARN sync worker-2 processed batch 1727 (orders, customers, products) in 107ms 12:04:32 INFO sync worker-3 processed batch 1744 (orders, customers, products) in 144ms 12:04:33 INFO sync worker-1 processed batch 1761 (orders, customers, products) in 181ms 12:04:34 INFO sync worker-2 processed batch 1778 (orders, customers, products) in 218ms 12:04:35 INFO sync worker-3 processed batch 1795 (orders, customers, products) in 115ms 12:04:36 INFO sync worker-1 processed batch 1812 (orders, customers, products) in 152ms 12:04:37 INFO sync worker-2 processed batch 1829 (orders, customers, products) in 189ms 12:04:38 WARN sync worker-3 processed batch 1846 (orders, customers, products) in 86ms 12:04:39 INFO sync worker-1 processed batch 1863 (orders, customers, products) in 123ms
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
const log = Array.from({ length: 40 }).map((_, i) => {
const second = String(i).padStart(2, "0")
const status = i % 7 === 3 ? "WARN" : "INFO"
return `12:04:${second} ${status} sync worker-${(i % 3) + 1} processed batch ${1200 + i * 17} (orders, customers, products) in ${80 + ((i * 37) % 140)}ms`
})
export function ScrollAreaBoth() {
return (
<ScrollArea className="h-64 w-full max-w-md rounded-lg border">
<pre className="w-max p-4 font-mono text-xs leading-5 text-muted-foreground">
{log.join("\n")}
</pre>
<ScrollBar orientation="horizontal" />
</ScrollArea>
)
}API Reference#
ScrollArea wraps Base UI's ScrollArea.Root (data-slot="scroll-area"), with a Viewport (scroll-area-viewport), a vertical ScrollBar and a Corner inside it. ScrollBar wraps ScrollArea.Scrollbar (scroll-area-scrollbar) and its Thumb (scroll-area-thumb) and takes orientation ("vertical" by default, or "horizontal").
See the Base UI Scroll Area documentation for every prop.