Component
ScrollArea
A scrolling region with a thin themed native scrollbar, for panels, menus, side lists and code blocks of fixed height. Native scrolling and the native scrollbar stay; only its color and width are styled (scrollbar-width thin, scrollbar-color). No custom drawn thumb. The page itself keeps the browser scrollbar.
Xem trước
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="min-w-0">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 09</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 10</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 11</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 12</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
</div>
</ScrollArea>Cách dùng
Khi nào dùng
- Keep a long list, panel or code block inside a fixed or maximum height while the page stays still.
- Give a scrollable region a thin native scrollbar that follows the current theme.
Khi nào không dùng
- The whole page should scroll with its content.
- A list is too long to scan and needs search. Use Combobox.
Biến thể
orientation
Which axes scroll.
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="min-w-0">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 09</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 10</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 11</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 12</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
</div>
</ScrollArea>
<ScrollArea orientation="horizontal" label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="flex gap-md p-md">
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="w-40 shrink-0 rounded-container border border-border bg-background-surface p-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
</div>
</ScrollArea>
<ScrollArea orientation="both" label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="w-160">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 09</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 10</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 11</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 12</p>
<p className="text-xs text-text-secondary">Updated workspace settings and shared the latest design with your team.</p>
</div>
</div>
</ScrollArea>type
auto shows the native scrollbar when content overflows; always reserves its space (scrollbar-gutter stable) so content does not shift.
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="min-w-0">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 09</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 10</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 11</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 12</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
</div>
</ScrollArea>
<ScrollArea type="always" label="Recent activity" className="h-48 w-64 max-w-full rounded-container border border-border">
<div className="min-w-0">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 09</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 10</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 11</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 12</p>
<p className="text-xs text-text-secondary">Updated just now</p>
</div>
</div>
</ScrollArea>Ví dụ
Recent activity
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="h-48 w-64 max-w-full rounded-container border border-border" label="Recent activity">
<div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
</div>
</ScrollArea>Horizontal projects
import { Card, CardContent } from "@/components/ui/card"
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea orientation="horizontal" className="h-40 w-64 max-w-full rounded-container border border-border" label="Projects">
<div className="flex gap-md p-md">
<Card className="w-40 shrink-0">
<CardContent>Website</CardContent>
</Card>
<Card className="w-40 shrink-0">
<CardContent>Mobile app</CardContent>
</Card>
<Card className="w-40 shrink-0">
<CardContent>Documentation</CardContent>
</Card>
</div>
</ScrollArea>Both axes
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea orientation="both" className="h-48 w-64 max-w-full rounded-container border border-border" label="Project updates">
<div className="w-160">
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
</div>
</ScrollArea>Reserved scrollbar space
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea type="always" className="max-h-48 w-64 max-w-full rounded-container border border-border" label="All projects">
<div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 01</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 02</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 03</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 04</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 05</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 06</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 07</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
<div className="border-b border-border px-md py-md">
<p className="text-sm font-medium">Project 08</p>
<p className="text-xs text-text-secondary">Updated workspace notes</p>
</div>
</div>
</ScrollArea>Nên và không nên
Nên
- Give the root a height or max height.
- Use in DropdownMenu or Combobox lists only if they need a themed bar; they already scroll natively.
- Provide enough content to overflow the chosen axis. Horizontal content needs a width greater than the viewport and must not shrink.
Không nên
- Do not wrap the whole page.
- Do not hide the scrollbar on content that the user must know scrolls without another cue.
Props
| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| orientation | enum | vertical | horizontal | both | vertical | Which axes scroll. |
| type | enum | auto | always | auto | auto shows the native scrollbar when content overflows; always reserves its space (scrollbar-gutter stable) so content does not shift. |
| label | string | - | - | Accessible name for the region when the viewport is focusable. |
| tabIndex | number | - | - | On the viewport: override automatic tab order. By default it takes focus only when it has no visible, enabled focusable children. |
| onScroll | React.UIEventHandler<HTMLDivElement> | - | - | On the viewport: native scroll event handler. |
| style | React.CSSProperties | - | - | On the viewport: inline styles for the native scrolling element. Set the outer dimensions with className. |
| className | string | - | - | On the outer box: supply height, max height, width, borders and corners. The viewport fills this box. |
Slot
| Tên | Bắt buộc | Mô tả |
|---|---|---|
| children | có | The content that scrolls. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | Outer box with a fixed or max height. |
| viewport | The scrolling element with overflow auto and the styled native scrollbar. |
Khả năng truy cập
Role: region
| Phím | Hành động |
|---|---|
| Tab | Focuses the viewport when it has no focusable children, so keyboard users can scroll. |
| Arrow keys / PageUp / PageDown / Home / End | Native scrolling on the enabled axes of the focused viewport. |
- Native scrolling stays: wheel, touch, momentum and find-in-page work.
- Pass aria-label when the viewport is focusable so the region has a name.
- Under reduced motion no smooth scrolling is added.
- The scrollbar is the browser's own, so it keeps its platform behavior (overlay scrollbars on touch, dragging, clicking the track).
Cài đặt
npx werewolf-ui add scroll-areaChạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.