Custom-scrollbar container. Hides the native scrollbar and renders a custom-painted track +
thumb on top of a scrollable viewport. The headless soma
layer owns the scroll math, the visibility timer (type) and the thumb
position; Eidos paints chrome only. Compound API mirrors Radix Primitives: explicit
Viewport / Scrollbar / Thumb / Corner
composition.
Scroll inside the framed box to observe the custom scrollbar painted by Eidos.
The thumb follows the soma-tracked scroll position; the track hover state is
driven by the morfo's data-hover marker.
{#each sampleItems as item}
{item} — body text continues across the line for horizontal scroll demos when the axis is wide enough.
All knobs are soma props — the headless layer
owns visibility timing and scroll math. The eidos
layer paints chrome with no additional props; tweak the recipe via the
--scroll-area-* custom properties.
soma props · headless behavior
eidos props · recipe sugar
Composition · which scrollbars to mount
somaheadless · scroll math + visibility timersvelte
{somaSnippet}
eidosvisual · pure pass-through of soma; recipe paints chromesvelte
{eidosSnippet}
{/if}
{#if tab === 'api'}
API reference
Pass-through from soma — no evaluative additions on the eidos layer. Visual tuning lives
in the recipe via --scroll-area-* custom properties.
ScrollArea (root)
Prop
Type
Default
Description
type
{types.map((t) => `'${t}'`).join(' | ')}
'hover'
Visibility behavior of the scrollbars.
scrollHideDelay
number
600
ms before hiding (only for 'hover' and 'scroll').
dir
'ltr' | 'rtl'
from Soma
Text direction. Affects horizontal scrollbar behavior.
ScrollArea.Scrollbar
Prop
Type
Default
Description
orientation
'vertical' | 'horizontal'
—
Required. Drives the recipe's data-orientation selector.
forceMount
boolean
false
Keep in DOM when hidden. Enables CSS transitions.
CSS tokens
Token
Default
Notes
--scroll-area-scrollbar-size
var(--space-2-5)
Inline-axis size of the track (and block-axis for horizontal).
--scroll-area-track-bg
color-mix(--color-neutral-track)
Track background, also used by the Corner.
--scroll-area-thumb-bg
var(--color-content-muted)
Thumb fill; hover state lifts to --color-content-secondary.
--scroll-area-thumb-min-size
var(--space-3)
Floor on the thumb so it stays grabable even on long content.
{'value' in attr && attr.value
? (attr as { value: { kind: string } }).value.kind
: '—'}
{/each}
{/if}
{#if ariaAttrs.length}
aria-attr
Source kind
Severity
{#each ariaAttrs as a}
{a.attr}
{a.value.kind}
{a.severity ?? 'required'}
{/each}
{/if}
{/if}
{/each}
{/if}
{#if tab === 'sema'}
sema · events
ScrollArea declares no semantic events. Scrolling is continuous and non-evaluative —
there is no commit / emerge / contact verb to project onto a perceptual channel. The
Scrollbar's data-state visibility transition is a CSS concern, not a sema
event. Consumers that need to react to scroll position read data-at-top /
data-at-bottom / data-at-left / data-at-right on
the Viewport — see the morfo declaration above.
{/if}
{#if tab === 'recipe'}
Eidos recipe
Recipe lives in src/uix/eidos/components/scroll-area/scroll-area.css. The
data-orientation attribute drives the geometry of the scrollbar; the
visibility states (data-state='visible' / 'hidden') come from
the soma timer.
Selector
Owner
Purpose
[data-scroll-area]
morfo
Provider marker. Sets up the relative-positioned shell.
[data-scroll-area-viewport]
morfo
Viewport marker. Receives overflow: auto from soma.
Square between the two scrollbars when both axes scroll.
{/if}
{#if tab === 'a11y'}
Accessibility
The custom scrollbar must remain reachable to keyboard and screen-reader users. The morfo
stamps the WAI-ARIA scrollbar role on every scrollbar with
aria-valuenow / aria-valuemin / aria-valuemax
bound to the soma-tracked scroll percentage.
ARIA contract
Part
Attribute
Value
scrollbar
role
'scrollbar'
scrollbar
aria-controls
id of viewport
scrollbar
aria-orientation
'vertical' | 'horizontal'
scrollbar
aria-valuenow / min / max
scroll percent (0–100)
scrollbar
aria-label
'Vertical scrollbar' / 'Horizontal scrollbar'
Other concerns
Concern
Contract
Keyboard
The viewport accepts native scroll keys (Arrow / Page / Home / End) when
focused. Browser keyboard handling is preserved; UIX does not steal arrow keys.
Focus visible
:focus-visible on the scrollbar exposes the canonical UIX focus
ring.
Touch
The Scrollbar declares touch-action: none so touch drags on the
custom thumb don't conflict with browser-native gestures.
RTL
Soma's dir prop is honoured: in RTL, the vertical scrollbar moves
to the inline-start side, matching native scrollbar positioning.