ScrollArea
A scroll container with thin, themed scrollbars over native scrolling.
Vertical
Hover or scroll to see the bar. Tab focuses the list; arrows and End scroll it.
Tags
Code
<ScrollArea class="tags" label="Tags">
<div class="list">
<h4>Tags</h4>
<div class="tag" e:for={tag of tags}>{tag}</div>
</div>
</ScrollArea>Usage
import { ScrollArea } from "@elements/ui/scroll-area";
<ScrollArea class="tags" label="Tags">
<h4>Tags</h4>
<div e:for={tag of tags}>{tag}</div>
</ScrollArea>
<ScrollArea orientation="horizontal" type="always">
<div class="row">...</div>
</ScrollArea>Examples
Horizontal
orientation horizontal with type always: the bar stays, the content scrolls sideways.
Code
<ScrollArea orientation="horizontal" type="always" class="gallery" label="Artwork">
<div class="row">
<figure e:for={work of works}>...</figure>
</div>
</ScrollArea>Types
When the bars show: hover (default), scroll, auto and always.
Code
<ScrollArea type="hover">...</ScrollArea> <!-- scrolling or pointer over -->
<ScrollArea type="scroll">...</ScrollArea> <!-- only while scrolling -->
<ScrollArea type="auto">...</ScrollArea> <!-- whenever it overflows -->
<ScrollArea type="always">...</ScrollArea> <!-- always -->Both axes
Two bars and a corner where they meet. The vertical bar stops above the corner.
Code
<ScrollArea orientation="both" type="auto" class="grid">
<table>...</table>
</ScrollArea>Growing content
type auto shows the bar once the content overflows, measured as it changes.
Code
<ScrollArea type="auto" class="list">
<div e:for={i of items}>Item {i}</div>
</ScrollArea>
<Button onclick={() => items++}>Add item</Button>Right to left
Under rtl the vertical bar sits on the left and horizontal scrolling starts at the right. The button switches the list's direction.
Code
<ScrollArea dir={state.dir} type="always">...</ScrollArea>
<Button onclick={() => state.dir = state.dir === "rtl" ? "ltr" : "rtl"}>Direction</Button>Scroll fade
The viewport carries each edge's overflow in px (--scroll-area-overflow-y-start and -end), here driving a mask that fades the edges with more to scroll. overflowEdgeThreshold sets when data-overflow-y-start turns on.
Code
<!-- The viewport carries each edge's overflow in px; mask the content with it.
overflowEdgeThreshold keeps data-overflow-y-start off for the first 8px. -->
<ScrollArea type="auto" overflowEdgeThreshold={8} class="fade">...</ScrollArea>
.fade .scroll-area-viewport {
mask-image: linear-gradient(to bottom,
transparent 0, black min(var(--space-10), var(--scroll-area-overflow-y-start)),
black calc(100% - min(var(--space-10), var(--scroll-area-overflow-y-end))), transparent 100%);
}Per-edge threshold
overflowEdgeThreshold also takes an object with xStart, xEnd, yStart and yEnd. Here the top edge turns on at once (yStart 0) and the bottom one turns off 40px before the end (yEnd 40).
Code
<!-- A threshold per edge: the top flag turns on at once, the bottom one
turns off 40px before the end. -->
<ScrollArea type="auto" overflowEdgeThreshold={{ yStart: 0, yEnd: 40 }} class="fade">...</ScrollArea>