Vertical scroll

The default — dir="y" — scrolls vertically. Set a fixed height to constrain the container.

Item 1 — scroll down to see more

Item 2 — scroll down to see more

Item 3 — scroll down to see more

Item 4 — scroll down to see more

Item 5 — scroll down to see more

Item 6 — scroll down to see more

Item 7 — scroll down to see more

Item 8 — scroll down to see more

Item 9 — scroll down to see more

Item 10 — scroll down to see more

<ScrollArea height={160}>
  <Stack gap="xs">
    {items.map((item) => <Text>{item}</Text>)}
  </Stack>
</ScrollArea>

Max height

Use maxHeight instead of height when the container should shrink to fit short content but scroll once it overflows.

Short list item 1

Short list item 2

Short list item 3

{/* Container shrinks to fit 3 items, scrolls if content grows past 200px */}
<ScrollArea maxHeight={200}>
  <Stack gap="xs">
    <Text>Item 1</Text>
    <Text>Item 2</Text>
    <Text>Item 3</Text>
  </Stack>
</ScrollArea>

Horizontal scroll

Set dir="x" for horizontal-only scrolling. Useful for wide tables or code blocks that shouldn't wrap.

Card 1

Card 2

Card 3

Card 4

Card 5

Card 6

Card 7

Card 8

Card 9

Card 10

Card 11

Card 12

<ScrollArea dir="x">
  <div style={{ display: 'flex', gap: 'var(--dv-spacing-md)', whiteSpace: 'nowrap' }}>
    {cards.map((card) => <Card key={card.id}>{card.title}</Card>)}
  </div>
</ScrollArea>

Both axes

Use dir="xy" to allow scrolling in both directions — handy for data grids or large canvas areas.

Row 1 — this content is wider than the container, scroll right to see it all

Row 2 — this content is wider than the container, scroll right to see it all

Row 3 — this content is wider than the container, scroll right to see it all

Row 4 — this content is wider than the container, scroll right to see it all

Row 5 — this content is wider than the container, scroll right to see it all

Row 6 — this content is wider than the container, scroll right to see it all

Row 7 — this content is wider than the container, scroll right to see it all

Row 8 — this content is wider than the container, scroll right to see it all

<ScrollArea dir="xy" height={160}>
  <div style={{ width: 600 }}>
    {rows.map((row) => <Text>{row}</Text>)}
  </div>
</ScrollArea>

Scrollbar visibility

The type prop controls when the scrollbar thumb is visible. The default 'auto' shows it only on hover or focus. Use 'always' to keep it permanently visible, or 'never' to hide it entirely (content is still scrollable).

type="auto"

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

type="always"

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

type="never"

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

{/* show on hover/focus (default) */}
<ScrollArea type="auto" height={200}>…</ScrollArea>

{/* always visible */}
<ScrollArea type="always" height={200}>…</ScrollArea>

{/* hidden but still scrollable */}
<ScrollArea type="never" height={200}>…</ScrollArea>

Scrollbar size

Adjust the scrollbar thumb thickness with scrollbarSize (pixels). Default is 6.

scrollbarSize=3

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

scrollbarSize=6

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

scrollbarSize=10

Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

<ScrollArea scrollbarSize={3} height={200}>thin thumb</ScrollArea>
<ScrollArea scrollbarSize={6} height={200}>default</ScrollArea>
<ScrollArea scrollbarSize={10} height={200}>thick thumb</ScrollArea>

Props

PropTypeDefaultDescription
type'auto'|'always'|'never''auto'When to show the scrollbar thumb
dir'x'|'y'|'xy''y'Which axis(es) scroll
heightnumber|stringFixed height of the scroll container (number = px)
maxHeightnumber|stringContainer grows to fit content up to this height, then scrolls
scrollbarSizenumber6Scrollbar thumb thickness in pixels
classstringAdditional CSS class names
stylestring|objectInline styles merged with generated CSS custom properties