ScrollArea
A custom scrollable container providing styled scrollbar overlays with drag-to-scroll support, configurable visibility behavior, and optional fade mask gradients at scroll boundaries. Designed for editor panels, sidebars, and content areas that need polished scrolling behavior beyond native scrollbars.
Live Preview
Import
import { ScrollArea } from 'entangle-ui';Usage
<ScrollArea maxHeight={300}> <div> {/* Long content that overflows */} {items.map(item => ( <Item key={item.id} {...item} /> ))} </div></ScrollArea>Scroll Direction
Control which axes can scroll using the direction prop.
{ /* Vertical only (default) */}<ScrollArea direction="vertical" maxHeight={200}> <LongVerticalContent /></ScrollArea>;
{ /* Horizontal only */}<ScrollArea direction="horizontal" maxWidth={400}> <WideHorizontalContent /></ScrollArea>;
{ /* Both axes */}<ScrollArea direction="both" maxHeight={300} maxWidth={500}> <LargeContent /></ScrollArea>;Scrollbar Visibility
The scrollbarVisibility prop controls when custom scrollbars appear.
{ /* Auto: show on scroll/hover, hide after delay (default) */}<ScrollArea scrollbarVisibility="auto" maxHeight={200}> <Content /></ScrollArea>;
{ /* Always visible */}<ScrollArea scrollbarVisibility="always" maxHeight={200}> <Content /></ScrollArea>;
{ /* Show only on hover */}<ScrollArea scrollbarVisibility="hover" maxHeight={200}> <Content /></ScrollArea>;
{ /* Never show scrollbars (still scrollable via wheel/touch) */}<ScrollArea scrollbarVisibility="never" maxHeight={200}> <Content /></ScrollArea>;| Mode | Behavior |
|---|---|
auto | Shows on scroll or hover, auto-hides after delay |
always | Scrollbars always visible when content overflows |
hover | Shows only while the mouse is over the scroll area |
never | Scrollbars hidden entirely (scroll still works via wheel/touch/keyboard) |
Auto-hide Delay
When using scrollbarVisibility="auto", control the delay before scrollbars fade out.
<ScrollArea scrollbarVisibility="auto" hideDelay={2000} maxHeight={200}> <Content /></ScrollArea>Fade Masks
Enable gradient fade masks at scroll boundaries to visually indicate more content is available.
<ScrollArea fadeMask maxHeight={200}> <Content /></ScrollArea>;
{ /* Custom fade mask size */}<ScrollArea fadeMask fadeMaskHeight={40} maxHeight={200}> <Content /></ScrollArea>;Fade masks appear at the top/bottom for vertical scrolling and left/right for horizontal scrolling. They automatically hide when the user has scrolled to the edge.
Scrollbar Customization
Fine-tune the scrollbar appearance with width, padding, and minimum thumb length.
<ScrollArea scrollbarWidth={8} scrollbarPadding={3} minThumbLength={40} maxHeight={300}> <Content /></ScrollArea>Auto Fill
When placed inside a flex or grid layout, use autoFill to make the scroll area fill its parent container.
<Flex direction="column" fullHeight> <Header /> <ScrollArea autoFill> <MainContent /> </ScrollArea> <Footer /></Flex>Scroll Callbacks
React to scroll position changes and boundary events.
<ScrollArea maxHeight={300} onScroll={e => console.log('Scrolled:', e.currentTarget.scrollTop)} onScrollTop={() => console.log('Reached top')} onScrollBottom={() => loadMoreItems()}> <Content /></ScrollArea>The onScrollBottom callback is useful for implementing infinite scrolling patterns.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Scrollable content. Required. |
direction | 'vertical' | 'horizontal' | 'both' | 'vertical' | Which axes can scroll. |
scrollbarVisibility | 'auto' | 'always' | 'hover' | 'never' | 'auto' | Scrollbar visibility behavior. |
hideDelay | number | 1000 | Delay in milliseconds before scrollbar auto-hides. Only applies when scrollbarVisibility is "auto". |
scrollbarWidth | number | 6 | Scrollbar track width in pixels. |
minThumbLength | number | 30 | Minimum scrollbar thumb length in pixels. |
scrollbarPadding | number | 2 | Padding between scrollbar track and content edge in pixels. |
fadeMask | boolean | false | Whether to show gradient fade masks at scroll boundaries. |
fadeMaskHeight | number | 24 | Height of the fade mask gradient in pixels. |
maxHeight | number | string | — | Maximum height of the scroll area. Required to enable vertical scrolling. |
maxWidth | number | string | — | Maximum width of the scroll area. Required to enable horizontal scrolling. |
autoFill | boolean | false | When true, sets width and height to 100% to fill the parent container. |
onScroll | (event: UIEvent<HTMLDivElement>) => void | — | Callback fired when the scroll position changes. |
onScrollTop | () => void | — | Callback fired when scroll reaches the top edge. |
onScrollBottom | () => void | — | Callback fired when scroll reaches the bottom edge. |
className | string | — | Additional CSS class names applied to the root element. |
style | CSSProperties | — | Inline styles applied to the root element. |
testId | string | — | Test identifier for automated testing. |
ref | Ref<HTMLDivElement> | — | Ref to the scrollable viewport element. |
The component also accepts all standard HTML <div> attributes on the root element.
Accessibility
- The scrollable viewport has
role="region"andtabIndex={0}for keyboard accessibility - Custom scrollbar tracks have
role="scrollbar"with properaria-controls,aria-orientation,aria-valuenow,aria-valuemin, andaria-valuemaxattributes - Content remains scrollable via keyboard (arrow keys, Page Up/Down, Home/End) regardless of scrollbar visibility setting
- Scrollbar thumb supports pointer drag interaction for precise scroll positioning