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";23<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 here10 </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:
| Slot | Element |
|---|---|
scroll-area | The root <div> element |
scroll-area-viewport | The clipping viewport that holds the scrollable content |
scroll-area-content | Wrapper around the content you render |
scroll-area-scrollbar | A scrollbar track (one per axis) |
scroll-area-thumb | The draggable thumb inside a scrollbar |
scroll-area-corner | The 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-labeloraria-labelledbyto label the scrollable content. When provided, the viewport is exposed as a labelledregionlandmark so screen-reader users can navigate to it.