Overview
Get Started
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 20 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-64 w-xs rounded-lg border">
<div className="flex flex-col gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex h-20 items-center justify-center rounded-md border bg-muted text-sm"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Installation
Copy and paste the following code into your project.
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
import { cn } from "@/lib/cn";
export function ScrollArea({
className,
children,
scrollFade = false,
scrollbarGutter = false,
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root> & {
scrollFade?: boolean;
scrollbarGutter?: boolean;
}) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn(
"size-full min-h-0 [--scrollbar-margin:--spacing(1)] [--scrollbar-size:--spacing(1.5)]",
className
)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className={cn(
"h-full rounded-[inherit] outline-none transition-shadows data-has-overflow-y:overscroll-y-contain data-has-overflow-x:overscroll-x-contain",
scrollFade &&
"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
scrollbarGutter &&
"data-has-overflow-y:pe-[calc(var(--scrollbar-size)+var(--scrollbar-margin))] data-has-overflow-x:pb-[calc(var(--scrollbar-size)+var(--scrollbar-margin))]"
)}
>
<ScrollAreaPrimitive.Content className="size-full">{children}</ScrollAreaPrimitive.Content>
</ScrollAreaPrimitive.Viewport>
<ScrollBar orientation="vertical" />
<ScrollBar orientation="horizontal" />
<ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" />
</ScrollAreaPrimitive.Root>
);
}
export function ScrollBar({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Scrollbar>) {
return (
<ScrollAreaPrimitive.Scrollbar
data-slot="scroll-area-scrollbar"
className={cn(
"pointer-events-none m-(--scrollbar-margin) flex rounded-full opacity-0 transition-opacity delay-300 data-hovering:pointer-events-auto data-scrolling:pointer-events-auto data-[orientation=horizontal]:h-(--scrollbar-size) data-[orientation=vertical]:w-(--scrollbar-size) data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100 data-hovering:delay-0 data-scrolling:delay-0 data-hovering:duration-100 data-scrolling:duration-100",
className
)}
orientation={orientation}
{...props}
>
<ScrollAreaPrimitive.Thumb
data-slot="scroll-area-thumb"
className="flex-1 rounded-full bg-neutral-400 dark:bg-neutral-600"
/>
</ScrollAreaPrimitive.Scrollbar>
);
}
export { ScrollAreaPrimitive };Usage
import { ScrollArea } from "@/components/ui/scroll-area";<ScrollArea className="h-64 rounded-md border">
<div className="p-4">
lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum.
</div>
</ScrollArea>Examples
Horizontal scroll
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 20 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-fit max-w-xs rounded-lg border">
<div className="inline-flex gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex h-20 w-40 shrink-0 items-center justify-center rounded-md border bg-muted text-sm"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Both horizontal and vertical scroll
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
Item - 20
Item - 21
Item - 22
Item - 23
Item - 24
Item - 25
Item - 26
Item - 27
Item - 28
Item - 29
Item - 30
Item - 31
Item - 32
Item - 33
Item - 34
Item - 35
Item - 36
Item - 37
Item - 38
Item - 39
Item - 40
Item - 41
Item - 42
Item - 43
Item - 44
Item - 45
Item - 46
Item - 47
Item - 48
Item - 49
Item - 50
Item - 51
Item - 52
Item - 53
Item - 54
Item - 55
Item - 56
Item - 57
Item - 58
Item - 59
Item - 60
Item - 61
Item - 62
Item - 63
Item - 64
Item - 65
Item - 66
Item - 67
Item - 68
Item - 69
Item - 70
Item - 71
Item - 72
Item - 73
Item - 74
Item - 75
Item - 76
Item - 77
Item - 78
Item - 79
Item - 80
Item - 81
Item - 82
Item - 83
Item - 84
Item - 85
Item - 86
Item - 87
Item - 88
Item - 89
Item - 90
Item - 91
Item - 92
Item - 93
Item - 94
Item - 95
Item - 96
Item - 97
Item - 98
Item - 99
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 100 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-80 w-xs rounded-lg border">
<div className="inline-grid grid-cols-[repeat(10,6.25rem)] grid-rows-[repeat(10,6.25rem)] gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex shrink-0 items-center justify-center rounded-md border bg-muted text-xs"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Scroll with fade effect
Pass scrollFade prop to ScrollArea to add fade effect at the edges.
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 20 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-64 w-xs rounded-lg border" scrollFade>
<div className="flex flex-col gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex h-20 items-center justify-center rounded-md border bg-muted text-sm"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Scrollbar gutter
Enable scrollbarGutter prop to add space for the scrollbar to avoid layout shift.
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 20 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-64 w-xs rounded-lg border" scrollbarGutter>
<div className="flex flex-col gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex h-20 items-center justify-center rounded-md border bg-muted text-sm"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Scrollbar custom size and margin
Customize the scrollbar size using CSS variable --scrollbar-size. Default size is 6px.
You can also customize the scrollbar margin using CSS variable --scrollbar-margin. Default margin is 4px.
Item - 0
Item - 1
Item - 2
Item - 3
Item - 4
Item - 5
Item - 6
Item - 7
Item - 8
Item - 9
Item - 10
Item - 11
Item - 12
Item - 13
Item - 14
Item - 15
Item - 16
Item - 17
Item - 18
Item - 19
Item - 20
Item - 21
Item - 22
Item - 23
Item - 24
Item - 25
Item - 26
Item - 27
Item - 28
Item - 29
Item - 30
Item - 31
Item - 32
Item - 33
Item - 34
Item - 35
Item - 36
Item - 37
Item - 38
Item - 39
Item - 40
Item - 41
Item - 42
Item - 43
Item - 44
Item - 45
Item - 46
Item - 47
Item - 48
Item - 49
Item - 50
Item - 51
Item - 52
Item - 53
Item - 54
Item - 55
Item - 56
Item - 57
Item - 58
Item - 59
Item - 60
Item - 61
Item - 62
Item - 63
Item - 64
Item - 65
Item - 66
Item - 67
Item - 68
Item - 69
Item - 70
Item - 71
Item - 72
Item - 73
Item - 74
Item - 75
Item - 76
Item - 77
Item - 78
Item - 79
Item - 80
Item - 81
Item - 82
Item - 83
Item - 84
Item - 85
Item - 86
Item - 87
Item - 88
Item - 89
Item - 90
Item - 91
Item - 92
Item - 93
Item - 94
Item - 95
Item - 96
Item - 97
Item - 98
Item - 99
import { ScrollArea } from "@/components/ui/scroll-area";
const tags = Array.from({ length: 100 }, (_, i) => `Item - ${i}`);
export function ScrollAreaDemo() {
return (
<ScrollArea className="h-80 w-xs rounded-lg border [--scrollbar-margin:--spacing(0.5)] [--scrollbar-size:--spacing(1)]">
<div className="inline-grid grid-cols-[repeat(10,6.25rem)] grid-rows-[repeat(10,6.25rem)] gap-2 p-4">
{tags.map((tag) => (
<div
key={tag}
className="flex shrink-0 items-center justify-center rounded-md border bg-muted text-xs"
>
{tag}
</div>
))}
</div>
</ScrollArea>
);
}Scroll area with max-height
If you want to use max-height instead of height for the ScrollArea component, you have to follow one of the following approaches:
- Set
display: flexandflex-direction: columnto theScrollAreacomponent. This will make theScrollAreacomponent take the full height of its parent container and allow it to scroll when the content exceeds the max-height.
<ScrollArea className="flex max-h-40 max-w-sm flex-col rounded-md border">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur laborum sequi laudantium
aliquid laboriosam corporis, reiciendis maxime sunt qui recusandae ducimus dolores libero
quibusdam nemo, voluptas, odio ea repudiandae provident. Ut, in praesentium. Error iste excepturi
dicta fuga sequi sit! Possimus aliquam ab sapiente explicabo! Modi sunt, quam ratione asperiores
aut officia cupiditate nesciunt adipisci optio nemo voluptatibus. Qui, impedit! Eligendi, ducimus
obcaecati! Libero dolor illum magni dolorem. Alias iste sunt veniam incidunt assumenda a aliquid
fuga, esse reiciendis perspiciatis, laboriosam maxime itaque? Dicta placeat tempore optio beatae
numquam aut? Consequatur laborum doloribus praesentium laudantium delectus illum, libero ullam
pariatur molestias suscipit modi. Accusantium vel officia quae perspiciatis, eius sapiente
pariatur quia incidunt beatae saepe blanditiis culpa? Voluptas, dolor rerum! Tenetur autem facere
molestiae velit ipsa aliquid officiis repudiandae quia dolorem tempora excepturi, culpa provident
harum? Modi quam consequatur asperiores qui quo? Qui mollitia molestias hic esse natus praesentium
error?
</ScrollArea>- Wrap the
ScrollAreacomponent inside a parent container and set thedisplay: gridto the parent container. This will make theScrollAreacomponent take the full height of its parent container and allow it to scroll when the content exceeds the max-height.
<div className="grid max-w-sm rounded-md border">
<ScrollArea className="max-h-40">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur laborum sequi laudantium
aliquid laboriosam corporis, reiciendis maxime sunt qui recusandae ducimus dolores libero
quibusdam nemo, voluptas, odio ea repudiandae provident. Ut, in praesentium. Error iste
excepturi dicta fuga sequi sit! Possimus aliquam ab sapiente explicabo! Modi sunt, quam ratione
asperiores aut officia cupiditate nesciunt adipisci optio nemo voluptatibus. Qui, impedit!
Eligendi, ducimus obcaecati! Libero dolor illum magni dolorem. Alias iste sunt veniam incidunt
assumenda a aliquid fuga, esse reiciendis perspiciatis, laboriosam maxime itaque? Dicta placeat
tempore optio beatae numquam aut? Consequatur laborum doloribus praesentium laudantium delectus
illum, libero ullam pariatur molestias suscipit modi. Accusantium vel officia quae perspiciatis,
eius sapiente pariatur quia incidunt beatae saepe blanditiis culpa? Voluptas, dolor rerum!
Tenetur autem facere molestiae velit ipsa aliquid officiis repudiandae quia dolorem tempora
excepturi, culpa provident harum? Modi quam consequatur asperiores qui quo? Qui mollitia
molestias hic esse natus praesentium error?
</ScrollArea>
</div>API Reference
Scroll Area props
Component type props
Prop
Type
Default
Expand prop details
Whether to enable scroll fade effect at the edges.
Type
booleanDefault
falseWhether to add space for the scrollbar to avoid layout shift.
Type
booleanDefault
falseScroll Area CSS variables
Component type props
Prop
Type
Default
Expand prop details
Custom size of the scrollbar.
Type
stringDefault
--spacing(1.5) /* 6px */Custom margin of the scrollbar.
Type
stringDefault
--spacing(1) /* 4px */