Rokkit
style density

Composability

Every Rokkit component exposes named snippet slots. Pass a snippet to replace any part of the component's rendering — item content, group headers, empty states — without forking the component or fighting with CSS overrides.

Why snippets, not slots

Svelte 5 snippets are the clean equivalent of render props or named slots from earlier eras. They keep your customization logic co-located with your usage, not inside the library, and they receive strongly-typed arguments (the item proxy, the index, etc.) so customization is type-safe.

The library handles data logic, keyboard navigation, and ARIA; you control the pixels.

itemContent — replace the inside of a row

The most common snippet is itemContent. Every selection component (List, Menu, Tree, Select, Grid) accepts it. The snippet receives a ProxyItem you can read fields off:

<List items={users}>
  {#snippet itemContent(proxy)}
    <span class="i-mdi:account" />
    <strong>{proxy.label}</strong>
    <em>{proxy.get('role')}</em>
  {/snippet}
</List>

The component still renders the row wrapper (the <button> with data-path that the navigator needs) — your snippet just fills the content inside.

groupContent — customize group headers

For collapsible / grouped components (List, Menu, Select) groupContent overrides the heading row of a group:

<Menu items={grouped}>
  {#snippet groupContent(proxy)}
    <span class="i-mdi:folder" />
    {proxy.label}
    <span class="count">{proxy.get('children').length}</span>
  {/snippet}
</Menu>

Per-item snippets

Set item.snippet = 'name' on a data row to opt that single row into a named snippet instead of the default. Useful when one item needs a special layout (e.g. a "create new…" row):

<List items={[
  ...users,
  { snippet: 'create', label: '+ New user' }
]}>
  {#snippet itemContent(proxy)}
    <span>{proxy.label}</span>
  {/snippet}

  {#snippet create(proxy)}
    <button class="primary">{proxy.label}</button>
  {/snippet}
</List>

Per-item snippets fall back to itemContent if the named snippet isn't defined, so you can introduce them progressively.

Layout-level snippets

Some components expose snippets for chrome around the rows:

Snippet Component Purpose
crumb BreadCrumbs Replace each crumb's content
slide Carousel Render slide i of count
tag SearchFilter Custom filter chip styling
content UploadTarget / Timeline Drop-zone body / per-step extra
header / footer Card Top + bottom zones inside the card
tooltipContent Tooltip Rich bubble body

Snippets receive ProxyItem, not your raw data

The proxy argument is a thin reactive wrapper around your row. Use proxy.label, proxy.value, proxy.get('field') — those resolve via your fields mapping, so the snippet keeps working when you rename source keys.