Scroll Area
A height-constrained region with a styled, cross-browser scrollbar.
@garn/ui/scroll-areaOn this page
Default
A fixed-height vertical list with a styled scrollbar.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add scroll-area- Registry
scroll-area- Deps
@radix-ui/react-scroll-area- Registry deps
utils
Import
import { ScrollArea, ScrollBar } from "@garn/ui/scroll-area";Anatomy
The parts this component is built from — compose them to assemble it.
ScrollAreaRequired[data-slot="scroll-area"]Root + Viewport; renders a vertical ScrollBar and a Corner. Children render inside the scrolling viewport.
ScrollBar[data-slot="scroll-bar"]The scrollbar track + thumb. orientation vertical (default) | horizontal — compose a horizontal bar for horizontal overflow.
Props
The component's public props and their types.
No component-specific props — this is a thin wrapper over its native element.
Styling
Target these data-slots and states, and remap these tokens, to restyle without forking the component.
[data-slot="scroll-area"]States
| Selector | State | Description |
|---|---|---|
[data-state=visible] | scrollbar-visible | Scrollbar shown — timing follows the Root `type` (auto | always | scroll | hover). |
[data-state=hidden] | scrollbar-hidden | Scrollbar hidden (e.g. `type="hover"` when not hovering). |
When to use
Give a height-constrained region its own styled scrollbar — a sidebar, a long list, a code block, a chat log.
Reach for something else when
- The whole page (let the document scroll natively)
- content that must never be clipped (let it flow)
- a few items that already fit.
Overview
ScrollArea gives a height-constrained region its own consistently-styled scrollbar — a sidebar, a long list, a code block, a chat log — instead of the OS default that varies by platform. ScrollArea is the root + viewport (children scroll inside), and ScrollBar is the track/thumb (vertical by default; add a horizontal one for horizontal overflow). Use it for a bounded scrolling pane; for whole-page scrolling, let the document scroll natively.
Guidelines
Use it for bounded regions, not the whole page. It shines on a fixed-height panel that needs to scroll independently with a tidy scrollbar; hijacking the document scroll is the wrong call. Give the region a real height constraint so there's something to scroll.
Never trap content behind a scrollbar users can't see. Ensure the area is keyboard-scrollable and that important content isn't hidden with no scroll cue; on touch, native momentum should still work. Add a horizontal ScrollBar only when content truly overflows sideways.
Keep the scrollbar legible and unobtrusive. Style it to read clearly against the surface without dominating it, and don't shrink the thumb so far it's hard to grab. Respect reduced-motion for any scroll animations.
Best practices
- Set an explicit height / max-height on the ScrollArea (or its container) so there's something to scroll.
- Keep important content reachable — don't hide the only copy of critical info behind a scroll region.
- Use the Root
type(auto / always / scroll / hover) to decide when the bar shows.
- Don't wrap the entire page — use native document scroll.
- Don't set a height that clips content without leaving a scroll affordance.
- Don't rely on
type="hover"as the only hint that more content exists.
Content guidelines
- The scroll region has no text of its own — give it an accessible label when it's a distinct, navigable area.
Troubleshooting
No scrollbar appears and content is cut off.
Cause. The ScrollArea (or its parent) has no bounded height, so there's no overflow to scroll.
Fix. Give the ScrollArea an explicit height / max-height.
Horizontal content doesn't get a scrollbar.
Cause. ScrollArea renders a vertical ScrollBar by default.
Fix. Compose a <ScrollBar orientation="horizontal" /> (and let the content exceed the viewport width).
Accessibility
- Native scrolling is preserved — wheel, touch, and keyboard (when the viewport has focus) all still work; the styled bar is an overlay.
- Set the Root `type` to control when the scrollbar appears; `auto`/`always` keep it discoverable for everyone.