# Sveltier
> A Svelte 5 UI framework with five built-in design languages, a zero-dependency theme engine and flash-free server-side theming.
## Setup
```sh
pnpm add sveltier
```
```svelte
{@render children()}
```
## Conventions
Install `sveltier`, wrap the app in `UIProvider` with at least one theme pack (for example `monolith` from `sveltier/themes/monolith`), and import components from `sveltier`.
- Every component takes the same names for the same things: `variant` (elevated, flat, tonal, outlined, text, plain), `size` (xs to xl), `density` (compact, default, comfortable), `color` (an intent such as primary or error, neutral, or a custom colour), `rounded`, `disabled`, `loading`.
- Content goes in snippets (`children`, `prepend`, `append`, `actions`), events are callback props (`onclick`), and two-way values use `bind:` (`bind:value`, `bind:selected`, `bind:open`).
- Every component passes other attributes to its root element, merges `class`, and exposes the element as a bindable `ref`.
- Defaults for a whole app or section go in the `defaults` of `UIProvider` or a `DefaultsProvider`, by component name; a prop on the component still wins.
## Components
### Alert
Docs: ./components/alert
A message about something that happened or needs attention.
```svelte
The card ending 4471 was declined by the issuer.
{#snippet actions()}
Try another card
{/snippet}
Transfer sent.
```
`AlertProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'tonal'` | Visual weight. |
| `color` | `Color` | `'info'` | The colour, when there is no `type` to take it from. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the padding. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | Corner rounding. `true` keeps the theme's radius. |
| `type` | `'info' \| 'success' \| 'warning' \| 'error'` | | What kind of message: sets the colour and the icon. Warnings and errors are announced at once (`role="alert"`), the others politely (`role="status"`). |
| `title` | `string` | | A short summary, above the text. |
| `icon` | `boolean` | `true` | Shows the icon of the `type`. |
| `open` | `boolean` | `true` | Shown while true; a closable alert sets it to false. Bindable. |
| `closable` | `boolean` | `false` | Adds a button that closes the alert and calls `onclose`. |
| `closeLabel` | `string` | | The name of the close button. Defaults to the locale's `close`. |
| `onclose` | `() => void` | | Called when the close button closes the alert. |
| `prepend` | `Snippet` | | Content in place of the type's icon. |
| `actions` | `Snippet` | | Buttons or links after the text, such as `Retry`. |
| `children` | `Snippet` | | The message. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
### Avatar
Docs: ./components/avatar
A picture of a person or an account: an image, or initials or an icon when there is none
or it fails to load.
```svelte
AM Alex Morgan
AM
```
`AvatarProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Width and height: the control height of the size. |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'tonal'` | How the fallback is painted. |
| `color` | `Color` | `'neutral'` | The colour of the fallback. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `'full'` | Corner rounding. |
| `src` | `string` | | The image. |
| `alt` | `string` | | Who or what the avatar shows, for screen readers. Leave it out when a name is shown next to the avatar: it is then decorative and hidden from them. |
| `children` | `Snippet` | | Initials or an icon, shown while there is no image or it failed to load. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLSpanElement \| null` | | The root element, bindable with `bind:ref`. |
### Badge
Docs: ./components/badge
A count or a dot pinned to the top end corner of its content, or standing alone in a line
when it has none. A count of 0 hides it.
```svelte
Savings
```
`BadgeProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `Color` | `'primary'` | The badge's fill. |
| `max` | `number` | `99` | Counts above it show as `max+`. |
| `content` | `number \| string` | | What the badge says: usually a count. |
| `dot` | `boolean` | `false` | A dot instead of the content. |
| `label` | `string` | | What the content counts, read after it by screen readers: `unread messages` reads "3 unread messages". With `dot`, the whole announcement. With an `id`, this text has the id `{id}-label`, for the `aria-describedby` of a button the badge is pinned to. |
| `children` | `Snippet` | | The content the badge is pinned to. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLSpanElement \| null` | | The root element, bindable with `bind:ref`. |
### Button
Docs: ./components/button
A button, or a link that looks like one (`href`). Every other attribute of `` and
`` passes through to the element.
```svelte
(open = true)}>New transfer
Cancel payment
```
`ButtonProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'flat'` | Visual weight. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Height and text size. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the height and padding, never the text. |
| `color` | `Color` | `'primary'` | The colour the variant is painted with. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | Corner rounding. `true` keeps the theme's radius. |
| `block` | `boolean` | `false` | Takes the full width of its container. |
| `disabled` | `boolean` | `false` | A disabled button cannot be focused or pressed; a disabled link loses its `href`. |
| `as` | `'button' \| 'a'` | | The element to render. Defaults to `'a'` when `href` is given, otherwise `'button'`. |
| `icon` | `boolean` | `false` | Square, for a single icon as the content. Give it an `aria-label`. |
| `loading` | `boolean` | `false` | Shows a spinner and ignores presses, while the button keeps focus and its label for screen readers, which also hear that it is loading. |
| `prepend` | `Snippet` | | Content before the label, usually an icon. |
| `append` | `Snippet` | | Content after the label, usually an icon. |
| `children` | `Snippet` | | The label. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLButtonElement \| HTMLAnchorElement \| null` | | The root element, bindable with `bind:ref`. |
### ButtonGroup
Docs: ./components/button-group
Buttons joined into one control: shared borders, square inner corners, and the same
variant, size, density and colour unless a Button says otherwise. Give it an `aria-label`.
```svelte
CSV
PDF
```
`ButtonGroupProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'outlined'` | The variant of the Buttons. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | The size of the Buttons. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | The density of the Buttons. |
| `color` | `Color` | `'primary'` | The colour of the Buttons. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | The rounding of the group's outer corners; inner corners are square. |
| `children` | `Snippet` | | The Buttons. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
### Card
Docs: ./components/card
A surface that groups content about one thing: a header, the content and actions. Links
and buttons inside it are what is clickable, not the card.
```svelte
{#snippet prepend()}SV {/snippet}
$12,480.00
{#snippet actions()}
Add money
Statement
{/snippet}
```
`CardProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'elevated'` | Visual weight: a raised surface by default. |
| `color` | `Color` | `'neutral'` | The colour the variant is painted with. Neutral cards use the theme's surface, text and border colours. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the padding and the space between sections. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | Corner rounding. `true` keeps the theme's radius. |
| `title` | `string` | | The title, in the header. |
| `subtitle` | `string` | | A line under the title. |
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | | Makes the title a heading of this level (``, ``…), so it is in the page's outline. Without it the title is styled text. |
| `prepend` | `Snippet` | | Content before the title, such as an avatar or an icon. |
| `append` | `Snippet` | | Content after the title, such as a menu button. |
| `actions` | `Snippet` | | Buttons or links at the bottom. |
| `children` | `Snippet` | | The content. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
### Chip
Docs: ./components/chip
A compact label: a tag (optionally `closable`), a filter that toggles (`selected`), an
action (`onclick`) or a link (`href`).
```svelte
Card
Transfer
```
`ChipProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'tonal'` | Visual weight. A selected chip is `flat`. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'sm'` | Height and text size. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the height and padding, never the text. |
| `color` | `Color` | `'neutral'` | The colour the variant is painted with. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | Corner rounding. `true` keeps the pill. |
| `disabled` | `boolean` | `false` | A disabled chip cannot be pressed; a disabled link loses its `href`. |
| `selected` | `boolean` | | Makes the chip a toggle button (`aria-pressed`) that flips it when pressed: a filter. Bindable. Shows a check while selected. |
| `closable` | `boolean` | `false` | Adds a button that removes the chip by calling `onclose`. Only for chips that are not themselves buttons or links. |
| `closeLabel` | `string` | | The name of the close button, such as `Remove Euro`. Defaults to the locale's `close`. |
| `onclose` | `() => void` | | Called by the close button. |
| `prepend` | `Snippet` | | Content before the label, usually an icon or an avatar. |
| `append` | `Snippet` | | Content after the label. |
| `children` | `Snippet` | | The label. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLSpanElement \| HTMLButtonElement \| HTMLAnchorElement \| null` | | The root element, bindable with `bind:ref`. |
### Divider
Docs: ./components/divider
A hairline between groups of content: an ` `, which assistive technology reads as a separator.
```svelte
Available
Pending
```
`DividerProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `vertical` | `boolean` | `false` | Runs top to bottom, between items in a row, and stretches to the row's height. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLHRElement \| null` | | The root element, bindable with `bind:ref`. |
### Icon
Docs: ./components/icon
An icon: SVG path data, or any icon of your own as `children`. Decorative unless it has a
`label`.
```svelte
```
`IconProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `path` | `string` | | SVG path data, filled with the current colour: the format of path-based icon sets such as Material Design Icons. Several shapes go in one string (`M… Z M… Z`). |
| `viewBox` | `string` | `'0 0 24 24'` | The coordinate box of `path`. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | | The text size the icon is drawn at, φ^½ larger. Without it, the icon follows the text around it. |
| `color` | `Color` | | The icon's colour. Without it, the icon takes the colour of the text around it. |
| `label` | `string` | | A name for an icon that means something on its own, for assistive technology. Without it, the icon is decorative and hidden from it. |
| `children` | `Snippet` | | Any other icon (an ``, an icon component), sized and coloured like a path. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLSpanElement \| null` | | The root element, bindable with `bind:ref`. |
### List and ListItem
Docs: ./components/list
A list of rows: `ListItem`s. Density and colour are set here, for every item.
```svelte
{#snippet append()}$12,480.00{/snippet}
```
`ListProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the height and padding of its items. |
| `color` | `Color` | `'primary'` | The colour of the active item. |
| `nav` | `boolean` | `false` | Rounded rows set in from the edges, for navigation. |
| `children` | `Snippet` | | The `ListItem`s. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLUListElement \| null` | | The root element, bindable with `bind:ref`. |
`ListItemProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | | The main line. |
| `subtitle` | `string` | | A second line, under the title. |
| `href` | `string` | | Makes the row a link. |
| `target` | `HTMLAnchorAttributes['target']` | | Where a link opens, as on ``. |
| `rel` | `string` | | The relationship of a link, as on ` `. |
| `onclick` | `(event: MouseEvent) => void` | | Makes the row a button that calls this. |
| `active` | `boolean` | `false` | The current page or the selected row: tinted in the list's colour, and `aria-current="page"` on a link. |
| `disabled` | `boolean` | `false` | A disabled row cannot be pressed; a disabled link loses its `href`. |
| `prepend` | `Snippet` | | Content before the text, such as an avatar or an icon. |
| `append` | `Snippet` | | Content after the row's link or button, such as a value or a menu button. |
| `children` | `Snippet` | | More content under the title and subtitle. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLLIElement \| null` | | The root element, bindable with `bind:ref`. |
### ProgressLinear and ProgressCircular
Docs: ./components/progress
A horizontal progress bar.
```svelte
62%
```
`ProgressLinearProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `Color` | `'primary'` | The colour of the bar; its track is a tint of it. |
| `value` | `number` | | How far along, from 0 to 100. Values outside are clamped. |
| `indeterminate` | `boolean` | `false` | Busy for an unknown time: no value, and moving. |
| `label` | `string` | | The name screen readers give the bar, such as `Uploading statement`. Defaults to the locale's `loading` when indeterminate and `progress` otherwise. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
`ProgressCircularProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `Color` | `'primary'` | The colour of the arc; its track is a tint of it. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | The diameter: the control height of the size. |
| `value` | `number` | | How far along, from 0 to 100. Values outside are clamped. |
| `indeterminate` | `boolean` | `false` | Busy for an unknown time: no value, and moving. |
| `label` | `string` | | The name screen readers give the bar, such as `Uploading statement`. Defaults to the locale's `loading` when indeterminate and `progress` otherwise. |
| `children` | `Snippet` | | Content in the centre, such as the percentage. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
### SegmentedControl
Docs: ./components/segmented-control
One choice among a few options, side by side, as a radio group with one tab stop. Name it
with `aria-label`.
```svelte
```
`SegmentedControlProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'elevated' \| 'flat' \| 'tonal' \| 'outlined' \| 'text' \| 'plain'` | `'elevated'` | How the selected segment is painted: a raised surface by default. |
| `color` | `Color` | `'neutral'` | The colour of the selected segment. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Height and text size. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the height and padding, never the text. |
| `rounded` | `boolean \| 'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `true` | Corner rounding. `true` keeps the theme's radius. |
| `options` | `readonly SegmentedControlOption[]` | | The choices, in order. |
| `value` | `T` | | The chosen value. Bindable. |
| `onchange` | `(value: T) => void` | | Called with the value the user picks. |
| `disabled` | `boolean` | `false` | Disables every option. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
### Skeleton
Docs: ./components/skeleton
A placeholder in the shape of content that is still loading. Hidden from assistive
technology: mark the region that is loading with `aria-busy="true"` instead.
```svelte
{#if loading}
{:else}
…
{/if}
```
`SkeletonProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `'text' \| 'rect' \| 'circle'` | `'text'` | Lines of text, a golden rectangle that fills the width (an image, a chart), or a circle (an avatar). |
| `lines` | `number` | `1` | Lines of text; the last of several is φ⁻¹ as wide. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | The diameter of a circle: the control height of the size. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLSpanElement \| null` | | The root element, bindable with `bind:ref`. |
### Tabs
Docs: ./components/tabs
Tabs and the panel of the selected one. Name the tab list with `aria-label` or
`aria-labelledby`, which go to it.
```svelte
{#snippet panel(item)}
{/snippet}
```
`TabsProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `color` | `Color` | `'primary'` | The colour of the selected tab and its underline. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Height and text size of the tabs. |
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | Multiplies the height and padding of the tabs, never the text. |
| `grow` | `boolean` | `false` | Tabs share the full width equally. |
| `items` | `readonly TabsItem[]` | | The tabs, in order. |
| `value` | `T` | | The selected tab. Bindable; the first enabled tab when not set. |
| `onchange` | `(value: T) => void` | | Called with the value of the tab the user selects. |
| `activation` | `'automatic' \| 'manual'` | `'automatic'` | `automatic` selects a tab as soon as the arrow keys reach it; `manual` waits for Enter or Space, for panels that are slow to show. |
| `panel` | `Snippet<[TabsItem]>` | | The content of the selected tab's panel. |
| `class` | `ClassValue \| null` | | Classes added after the component's own: a string, an array or an object. |
| `ref` | `HTMLDivElement \| null` | | The root element, bindable with `bind:ref`. |
## Primitives
Behaviour for your own components: attachments (`{@attach focusTrap()}`) and helpers.
### focusTrap
Docs: ./primitives/focus
`FocusTrapOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `initialFocus` | `FocusableElement \| string \| false` | | Where focus goes when the trap starts, unless it is already inside: an element, a selector inside the container, or `false` to leave it where it is. Defaults to the first tabbable element, else the container. |
| `returnFocus` | `boolean \| FocusableElement \| null` | | Where focus goes when the trap ends: `true` for the element that had it when the trap started, an element (pass the trigger: Safari does not focus a button on click, so the element that had focus may be the page itself), or `false` to leave it. Defaults to `true`. |
### rovingFocus
Docs: ./primitives/focus
`RovingFocusOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `orientation` | `'horizontal' \| 'vertical' \| 'both'` | | Which arrow keys move: left/right, up/down, or both. Defaults to `'horizontal'`. |
| `loop` | `boolean` | | Wrap from the last item to the first and back. Defaults to `true`. |
| `items` | `string` | | Selector for the items, inside the container. Defaults to `[data-sv-item]`. |
### dismissable
Docs: ./primitives/layers
`DismissableOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `onDismiss` | `(reason: DismissReason) => void` | | Called when the user dismisses the layer. The component decides whether to close. |
| `escape` | `boolean` | | Dismiss on Escape, unless something inside handled it first. Defaults to `true`. |
| `outside` | `boolean` | | Dismiss on a pointer press outside. Defaults to `true`. |
| `focusOutside` | `boolean` | | Dismiss when focus moves outside, as menus do on Tab. Defaults to `false`. |
| `inside` | `Elements \| (() => Elements)` | | Elements that count as inside, such as the trigger, which toggles instead. |
### Portal
Docs: ./primitives/modality
`PortalProps`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `target` | `HTMLElement \| string` | | Where the content goes: an element or a selector. Defaults to `document.body`. |
| `children` | `Snippet` | | |
### anchored
Docs: ./primitives/positioning
`AnchoredOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `anchor` | `Element \| null \| undefined` | | The element to place against. Nothing happens until it exists. |
| `side` | `'top' \| 'bottom' \| 'start' \| 'end'` | | Defaults to `'bottom'`. |
| `align` | `'start' \| 'center' \| 'end'` | | Defaults to `'start'`. |
| `offset` | `number` | | Gap between the anchor and the floating element, in px. Defaults to 5. |
| `flip` | `boolean` | | Move to the opposite side when there is not enough room. Defaults to `true`. |
### typeahead
Docs: ./primitives/keyboard
`TypeaheadOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `string` | | Selector for the items, inside the container. Defaults to `[data-sv-item]`. |
| `timeout` | `number` | | How long typed characters keep building one search, in ms. Defaults to 500. |
| `onMatch` | `(item: HTMLElement) => void` | | What a match does. Defaults to focusing the item. |
### Motion transitions
Docs: ./primitives/motion
`TransitionOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `duration` | `number` | | In ms. Defaults to the theme's normal duration. |
| `delay` | `number` | | |
### virtualList
Docs: ./primitives/virtual-lists
`VirtualListOptions`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `count` | `number` | | How many items the list has. |
| `itemSize` | `number \| ((index: number) => number)` | | Item height in px: one number when every item is as tall, or an estimate per index. Items with the `measure` attachment are measured, and the measurement wins. |
| `overscan` | `number` | | Items rendered beyond each edge of the viewport. Defaults to 3. |
| `key` | `(index: number) => VirtualKey` | | A stable key per item, so measured heights follow items that move. Defaults to the index. Once items are measured it is read for every item when sizes change: keep large data in `$state.raw`, not deep `$state`. |
| `ssrHeight` | `number` | | Viewport height in px assumed until the viewport is measured, as on the server. Defaults to 0. |
`VirtualList`:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `VirtualItem[]` | | The items to render: those in view, plus the overscan. |
| `totalSize` | `number` | | Height of all the items together in px: the height of the element that holds them. |
| `viewport` | `Attachment` | | For the scroll container. |
| `measure` | `Attachment` | | For item elements, with `data-index={item.index}`, to measure their real height. |
| `scrollToIndex` | `(index: number, options?: ScrollToIndexOptions) => void` | | Scrolls the viewport, at once, so the item is in view, and renders it in the same update. Indexes outside the list are ignored. |