Scroll Area

A customizable scrollable container component with smooth scrolling, hover effects, and automatic scrollbar handling. Both vertical and horizontal scrollbars are automatically rendered and shown based on content overflow.

Overview

Both scrollbars are always rendered and appear only when content overflows, so a container never jumps as content grows. The scrollbar widens from 4px to 6px on hover, a corner element is added automatically when both axes are visible, and scrolling chains to the parent page once you reach a boundary. Use the type prop to control when scrollbars appear.

Anatomy

Import and assemble the component:

1import { ScrollArea } from "@raystack/apsara";
2
3<ScrollArea />

Usage

Which axes scroll, and whether the scrollbars take up space or float above the content.

Vertical scrolling

A basic vertical scroll area with a list of items. The scrollbar automatically appears when content overflows vertically.

1<ScrollArea style={{ height: "200px", width: "300px" }}>
2 <Flex direction="column" gap={2}>
3 {Array.from({ length: 30 }, (_, i) => (
4 <Text key={i} size="small">
5 Item {i + 1}
6 </Text>
7 ))}
8 </Flex>
9</ScrollArea>

Horizontal scrolling

A horizontal scroll area for wide content like tables or card grids. The scrollbar automatically appears when content overflows horizontally.

1<ScrollArea style={{ height: "150px", width: "300px" }}>
2 <Flex direction="row" gap={4} style={{ width: "600px" }}>
3 {Array.from({ length: 10 }, (_, i) => (
4 <Flex key={i} direction="column" gap={2} style={{ minWidth: "150px" }}>
5 <Text weight="medium" size="small">
6 Column {i + 1}
7 </Text>
8 <Text size="small" variant="secondary">
9 Content here
10 </Text>
11 </Flex>
12 ))}
13 </Flex>
14</ScrollArea>

Both scrollbars

When content overflows both vertically and horizontally, both scrollbars appear automatically along with the corner element.

1<ScrollArea style={{ height: "200px", width: "300px" }}>
2 <Flex direction="row" gap={4} style={{ width: "800px" }}>
3 {Array.from({ length: 15 }, (_, i) => (
4 <Flex key={i} direction="column" gap={2} style={{ minWidth: "180px" }}>
5 <Text weight="medium" size="small">
6 Column {i + 1}
7 </Text>
8 {Array.from({ length: 20 }, (_, j) => (
9 <Text key={j} size="small" variant="secondary">
10 Row {j + 1}
11 </Text>
12 ))}
13 </Flex>
14 ))}
15 </Flex>

Scrollbar type

Control when the scrollbar appears using the type prop.

1<ScrollArea style={{ height: "200px", width: "300px" }} type="hover">
2 <Flex direction="column" gap={2}>
3 {Array.from({ length: 20 }, (_, i) => (
4 <Text key={i} size="small">
5 Item {i + 1}
6 </Text>
7 ))}
8 </Flex>
9</ScrollArea>

API Reference

The Scroll Area component extends standard HTML div attributes, so you can use props like style, id, onClick, and other standard HTML attributes in addition to the props listed below.

Prop

Type

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
scroll-areaThe root <div> element
scroll-area-viewportThe clipping viewport that holds the scrollable content
scroll-area-contentWrapper around the content you render
scroll-area-scrollbarA scrollbar track (one per axis)
scroll-area-thumbThe draggable thumb inside a scrollbar
scroll-area-cornerThe corner between scrollbars (when both axes overflow)

Accessibility

  • Scrollable region is keyboard accessible.
  • Scrollbar elements are hidden from screen readers with aria-hidden.
  • Supports standard scrolling keyboard shortcuts.
  • Pass aria-label or aria-labelledby to label the scrollable content. When provided, the viewport is exposed as a labelled region landmark so screen-reader users can navigate to it.