Features
- Supports vertical and horizontal scrolling.
- Shows custom scrollbars when content overflows.
- Supports
visible,hover, andhiddenscrollbar modes. - Supports responsive
width,height,maxWidth, andmaxHeight. - Reports scroll progress and provides a ref to the scrolling element.
Vertical Scrolling
Set height to limit the viewport; taller content scrolls. Without height or maxHeight, Scroll Area fills its parent's height.
scrollableAttributes go to the focusable scrolling element, so pass its role and aria-label there. attributes and className go to the outer wrapper.
import { ScrollArea, Stack, Text } from "@vortexlabs/vortex";
export const ScrollAreaExample = () => {
return (
<ScrollArea
height="12rem"
width="100%"
scrollbar="visible"
scrollableAttributes={{ role: "region", "aria-label": "Activity log" }}
>
<Stack gap={3} padding={4}>
{Array.from({ length: 12 }, (_, index) => (
<Text key={index}>Activity entry {index + 1}</Text>
))}
</Stack>
</ScrollArea>
);
};Scrollbar Visibility
Set scrollbar to visible, hover, or hidden. The default is hover. Hidden scrollbars still allow wheel, touch, and keyboard scrolling.
import { ScrollArea, Stack, Text } from "@vortexlabs/vortex";
export const ScrollAreaVisibilityExample = () => {
return (
<Stack direction={{ xs: "column", md: "row" }} gap={4} width="100%">
{(["visible", "hover", "hidden"] as const).map((scrollbar) => (
<Stack key={scrollbar} gap={2} width="100%">
<Text weight="medium">{scrollbar}</Text>
<ScrollArea
height="8rem"
scrollbar={scrollbar}
scrollableAttributes={{
role: "region",
"aria-label": scrollbar + " scrollbar example",
}}
>
<Stack gap={3} padding={3}>
{Array.from({ length: 8 }, (_, index) => (
<Text key={index}>Update {index + 1}</Text>
))}
</Stack>
</ScrollArea>
</Stack>
))}
</Stack>
);
};Horizontal Scrolling
Limit width or maxWidth; wider content scrolls horizontally.
import { ScrollArea, Stack, Text } from "@vortexlabs/vortex";
export const ScrollAreaHorizontalExample = () => {
return (
<ScrollArea
width="100%"
maxWidth="28rem"
height="9rem"
scrollbar="visible"
scrollableAttributes={{ role: "region", "aria-label": "Release milestones" }}
>
<Stack direction="row" width="54rem" padding={4} gap={4}>
{["Design", "Build", "Review", "Release"].map((phase) => (
<Stack
key={phase}
width="12rem"
padding={4}
backgroundColor="surface-subtlest"
borderRadius="md"
>
<Text weight="medium">{phase}</Text>
<Text size="body-sm-desktop">Project milestone</Text>
</Stack>
))}
</Stack>
</ScrollArea>
);
};Responsive Size
Use a breakpoint object for height, maxHeight, width, or maxWidth. When you set only maxHeight, Scroll Area also uses it as the height.
import { ScrollArea, Stack, Text } from "@vortexlabs/vortex";
export const ScrollAreaResponsiveExample = () => {
return (
<ScrollArea
maxHeight={{ xs: "10rem", md: "16rem" }}
width="100%"
scrollbar="visible"
scrollableAttributes={{ role: "region", "aria-label": "Review checklist" }}
>
<Stack gap={3} padding={4}>
{Array.from({ length: 10 }, (_, index) => (
<Text key={index}>Review item {index + 1}</Text>
))}
</Stack>
</ScrollArea>
);
};Scroll Position
onScroll reports scroll progress as { x, y }, each from 0 at the start to 1 at the end. ref points to the scrolling element, so you can call native methods like scrollTo.
"use client";
import { Button, ScrollArea, Stack, Text } from "@vortexlabs/vortex";
import { useRef, useState } from "react";
export const ScrollAreaPositionExample = () => {
const viewportRef = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
return (
<Stack gap={3} width="100%">
<Stack direction="row" gap={3} align="center" wrap>
<Button
size="sm"
variant="secondary"
onClick={() => viewportRef.current?.scrollTo({ top: 0 })}
>
Back to top
</Button>
<Text>Scroll progress: {Math.round(position.y * 100)}%</Text>
</Stack>
<ScrollArea
ref={viewportRef}
onScroll={setPosition}
height="10rem"
scrollbar="visible"
scrollableAttributes={{ role: "region", "aria-label": "Project history" }}
>
<Stack gap={3} padding={4}>
{Array.from({ length: 15 }, (_, index) => (
<Text key={index}>History entry {index + 1}</Text>
))}
</Stack>
</ScrollArea>
</Stack>
);
};Accessibility
aria-label in scrollableAttributes.