|
|
5 months ago | |
|---|---|---|
| .. | ||
| components | 5 months ago | |
| README.md | 5 months ago | |
| exports.ts | 5 months ago | |
| index.ts | 6 months ago | |
| langs.ts | 6 months ago | |
| scroll-area-provider.svelte.test.ts | 5 months ago | |
| scroll-area-provider.svelte.ts | 5 months ago | |
| types.ts | 5 months ago | |
README.md
ScrollArea
Custom scrollbar component that replaces native scrollbars with styled ones. Supports both axes simultaneously, visibility modes, thumb drag, position tracking, and ARIA scrollbar semantics.
Anatomy
<ScrollArea.Provider>
<ScrollArea.Viewport>
<!-- scrollable content -->
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="vertical">
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
<ScrollArea.Scrollbar orientation="horizontal">
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
<ScrollArea.Corner />
</ScrollArea.Provider>
Native scrollbars are hidden via CSS. Custom scrollbars are positioned absolutely within the root container.
Parts
| Part | Element | Description |
|---|---|---|
Provider |
<div> |
Root container. Manages type, delay, overflow tracking. Position: relative. |
Viewport |
<div> |
Scrollable content area. Native scrollbars hidden. Reports scroll position and content size. |
Scrollbar |
<div> |
Custom scrollbar track. One per axis. ARIA scrollbar role. Handles click-to-scroll. |
Thumb |
<div> |
Draggable scroll thumb. Size proportional to viewport/content ratio. Pointer capture drag. |
Corner |
<div> |
Fills space where horizontal and vertical scrollbars meet. Only visible when both axes overflow. |
ARIA
| Part | Attribute | Value |
|---|---|---|
| Scrollbar | role |
scrollbar |
| Scrollbar | aria-controls |
ID of Viewport |
| Scrollbar | aria-valuenow |
Current scroll percentage (0-100) |
| Scrollbar | aria-valuemin |
0 |
| Scrollbar | aria-valuemax |
100 |
| Scrollbar | aria-orientation |
horizontal | vertical |
Data Attributes
| Part | Attribute | Values |
|---|---|---|
| Provider | data-scroll-area |
Always present |
| Provider | data-overflow-x |
Present when content overflows horizontally |
| Provider | data-overflow-y |
Present when content overflows vertically |
| Viewport | data-scroll-area-viewport |
Always present |
| Viewport | data-at-top |
Present when scrolled to top |
| Viewport | data-at-bottom |
Present when scrolled to bottom |
| Viewport | data-at-left |
Present when scrolled to left edge |
| Viewport | data-at-right |
Present when scrolled to right edge |
| Viewport | data-overflow-x |
Present when content overflows horizontally |
| Viewport | data-overflow-y |
Present when content overflows vertically |
| Scrollbar | data-scroll-area-scrollbar |
Always present |
| Scrollbar | data-state |
visible | hidden |
| Scrollbar | data-orientation |
horizontal | vertical |
| Scrollbar | data-hover |
Present when hovered |
| Scrollbar | data-dragging |
Present when thumb is being dragged |
| Scrollbar | data-overflow-x |
Present when content overflows horizontally |
| Scrollbar | data-overflow-y |
Present when content overflows vertically |
| Thumb | data-scroll-area-thumb |
Always present |
| Thumb | data-state |
visible | hidden |
| Thumb | data-orientation |
horizontal | vertical |
| Thumb | data-hover |
Present when scrollbar is hovered |
| Thumb | data-dragging |
Present when being dragged |
| Corner | data-scroll-area-corner |
Always present |
| Corner | data-state |
visible | hidden |
CSS Variables
| Variable | Part | Description |
|---|---|---|
--scroll-area-corner-width |
Provider | Corner width (scrollbar size when both axes overflow) |
--scroll-area-corner-height |
Provider | Corner height |
--scroll-area-scrollbar-size |
Provider (consumer sets) | Scrollbar track width/height (default 8px) |
--scroll-area-thumb-width |
Thumb | Computed thumb width |
--scroll-area-thumb-height |
Thumb | Computed thumb height |
Keyboard
Keyboard scrolling uses native browser behavior (arrow keys, Page Up/Down, Home/End, Space) on the viewport. No custom keyboard handlers on the scrollbar.
Behavior
Visibility modes
| Mode | Behavior |
|---|---|
hover |
Show scrollbars when pointer enters the root area. Hide after delay. |
scroll |
Show scrollbars during active scrolling. Hide after delay. |
auto |
Always visible when content overflows. |
always |
Permanently visible regardless of overflow. |
Thumb size
Proportional to the visible area: thumbSize = trackLength * (viewportSize / contentSize). Minimum 20px to remain clickable.
Thumb drag
Uses pointer capture for reliable tracking. The scroll position updates proportionally to thumb displacement on the track.
Click on track
Clicking on the scrollbar track (not the thumb) scrolls to that position proportionally.
Position tracking
The viewport exposes data-at-top, data-at-bottom, data-at-left, data-at-right for styling scroll shadows or sticky headers.
Usage
Basic (vertical only)
<script>
import { ScrollArea } from '$soma/components';
</script>
<ScrollArea.Provider>
<ScrollArea.Viewport>
<!-- long content -->
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="vertical">
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
</ScrollArea.Provider>
Both axes
<ScrollArea.Provider>
<ScrollArea.Viewport>
<!-- wide + tall content -->
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="vertical">
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
<ScrollArea.Scrollbar orientation="horizontal">
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
<ScrollArea.Corner />
</ScrollArea.Provider>
Always visible
<ScrollArea.Provider type="always">
<!-- scrollbars always shown -->
</ScrollArea.Provider>
Auto (visible when overflowing)
<ScrollArea.Provider type="auto">
<!-- scrollbars shown only when content overflows -->
</ScrollArea.Provider>
Scroll shadows via position tracking
[data-scroll-area-viewport]:not([data-at-top]) {
box-shadow: inset 0 8px 6px -6px rgba(0, 0, 0, 0.1);
}
[data-scroll-area-viewport]:not([data-at-bottom]) {
box-shadow: inset 0 -8px 6px -6px rgba(0, 0, 0, 0.1);
}
Comparison with reference libraries
| Feature | Radix | Ark | Bits | Soma |
|---|---|---|---|---|
| Parts | Root, Viewport, Scrollbar, Thumb, Corner | Root, Viewport, Scrollbar, Thumb, Corner | Root, Viewport, Scrollbar, Thumb, Corner | Provider, Viewport, Scrollbar, Thumb, Corner |
| Visibility modes | hover/scroll/auto/always | Custom (context) | hover/scroll/auto/always | hover/scroll/auto/always |
scrollHideDelay |
Yes (600ms) | No | Yes (600ms) | Yes (600ms) |
dir (RTL) |
Yes | No | Yes | Yes |
forceMount on Scrollbar |
No | No | Yes | Yes |
| ARIA scrollbar role | Yes | No (context) | Implicit | Yes |
aria-valuenow/min/max |
Yes | No | No | Yes |
aria-orientation |
Yes | Yes | Implicit | Yes |
data-state visible/hidden |
Yes | No | Yes | Yes |
data-hover |
No | Yes | No | Yes |
data-dragging |
No | Yes | No | Yes |
data-overflow-x/y |
No | Yes | No | Yes |
data-at-top/bottom/left/right |
No | Yes | No | Yes |
| CSS vars (corner) | Yes | Yes | No | Yes |
| CSS vars (thumb size) | No | Yes | No | Yes |
| Click on track | Yes | Yes | Yes | Yes |
| Thumb drag (pointer capture) | Yes | Yes | Yes | Yes |
| Position tracking | No | Yes (context API) | No | Yes (data-* attrs) |
| Both axes simultaneously | Yes | Yes | Yes | Yes |
| Pointer capture cleanup | Yes | Yes (v2.15.5) | Yes | Yes |