scroll-area
Augments native scroll functionality for custom, cross-browser styling.
Philosophy
ScrollArea keeps the browser's own scrolling and scrollbar, so scroll physics, keyboard scrolling, and screen readers work as they do everywhere else. You style the scrollbar once in your global CSS and every ScrollArea picks it up. The API stays small (viewportClassName and viewportRef) because scrolling should be invisible infrastructure, not a feature you configure.
Installation
npx @gentleduck/cli add scroll-area
npx @gentleduck/cli add scroll-area
/* Add this block of css to your project. */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-corner {
background: transparent;
}
::-webkit-scrollbar-thumb {
/* Replace this with your own custom scrollbar thumb color */
background: var(--border);
border-radius: 5px;
}
Usage
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
Jokester began sneaking into the castle in the middle of the night and leaving
jokes all over the place: under the king's pillow, in his soup, even in the
royal toilet. The king was furious, but he couldn't seem to stop Jokester. And
then, one day, the people of the kingdom discovered that the jokes left by
Jokester were so funny that they couldn't help but laugh. And once they
started laughing, they couldn't stop.
</ScrollArea>
Examples
Horizontal Scrolling
Scrollbar
The viewport shows the native scrollbar, styled by the ::-webkit-scrollbar rules from the installation step. Chromium and Safari use those rules; Firefox ignores them and draws its own thin scrollbar.
To keep scrolling but hide the bar, pass scrollbar-none to the viewport. Use it sparingly: without a bar, nothing tells people the content scrolls.
<ScrollArea className="h-48" viewportClassName="scrollbar-none">
...
</ScrollArea>
RTL Support
Set the direction once with DirectionProvider (or <html dir="rtl">) and the scroll area follows it. No dir prop or rtl: classes needed.
Motion
Use MotionScrollArea for a smooth entrance animation powered by motion. The container uses the shared scaleIn preset (fade, scale, and blur) with a springBouncy transition on mount.
motion package. Use MotionScrollArea instead of ScrollArea. Same props. The regular ScrollArea is perfectly fine - this is an optional enhancement.API Reference
ScrollArea
| Prop | Type | Default | Description |
|---|---|---|---|
dir | 'ltr' | 'rtl' | - | Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> <html dir>). |
viewportRef | React.Ref<HTMLDivElement> | - | Ref forwarded to the inner scrollable viewport element |
viewportClassName | string | -- | Additional CSS classes for the inner scrollable viewport. Pass scrollbar-none to hide the scrollbar |
className | string | -- | Additional CSS classes for the outer container |
style | React.CSSProperties | -- | Inline styles for the outer container |
children | React.ReactNode | -- | Scrollable content |
...props | React.HTMLProps<HTMLDivElement> | - | Additional props to spread to the content div |
MotionScrollArea
scaleIn entrance (fade, scale, and blur) with springBouncy transition on mount. Requires the motion package.
| Prop | Type | Default | Description |
|---|---|---|---|
...props | ScrollAreaProps | - | All props from ScrollArea are supported (drag handlers are omitted for motion type safety) |