Data Display

DataList

Semantic list container for homogeneous record rows, with a styled empty state and an optional list-level density.

import { DataList } from '@lostgradient/cinder/data-list';
listiterator
01

Overview

A semantic list container (<ul role="list">) for a homogeneous collection of records. DataList owns the list element, the list reset, and the empty state; it delegates row chrome (padding, dividers, density) to the row primitive. Each record is rendered through the children snippet, which must render an <li>StackedListItem is the recommended row.

Reach for DataList when you have a vertical list of like records. For key–value metadata about a single entity use DescriptionList; for tabular rows and columns use Table.

Usage

svelte
<script lang="ts">
  import { DataList } from '@lostgradient/cinder/data-list';
  import { StackedListItem } from '@lostgradient/cinder/stacked-list-item';

  const members = [
    { id: 'a', name: 'Alice Chen', role: 'Engineer' },
    { id: 'b', name: 'Bob Osei', role: 'Designer' },
  ];
</script>

<DataList items={members} key={(member) => member.id} density="condensed">
  {#snippet children(member)}
    <StackedListItem>
      {#snippet title()}{member.name}{/snippet}
      {#snippet meta()}{member.role}{/snippet}
    </StackedListItem>
  {/snippet}
  {#snippet empty()}
    No members yet.
  {/snippet}
</DataList>

A list-level density is inherited by every StackedListItem row that does not set its own density prop. The empty snippet renders inside a component-owned <li class="cinder-data-list-empty">, so it needs no inline styling.

Live preview
02

When to use

Use when
  • Rendering a vertical list of like records where each row shares the same layout.
  • Pairing with StackedListItem rows for leading/title/description/meta/trailing content.
  • Showing a dedicated empty state when the collection has no items.
Avoid when
  • Presenting key-value metadata for a single entity — use description-list instead.
  • Rendering tabular data with rows and columns — use table instead.
03

Examples

Basic data list

A list of homogeneous records. DataList is the semantic `<ul role="list">` container; each row is a StackedListItem with a title and trailing meta. Row chrome (padding, dividers, density) is owned by the row, so content stays compactly aligned instead of stretching to the viewport edges.

Empty state fallback

When items is empty, the empty snippet renders inside a component-owned `<li class="cinder-data-list-empty">` — centered, muted padding, no inline styles required.

04

Props

Props for data-list
Name Type Default Required Bindable Description
items T[] req The records to render. Each is passed to children.
key (item: T) => string | number req Key extractor for stable DOM reconciliation. Svelte uses this to identify each row when the list is reordered, filtered, or updated. Without a key, rows are matched by index and the wrong row instances may receive updated props, causing O(n) churn and incorrect rendering. ``svelte <DataList {items} key={(m) => m.id}> ``
density 'comfortable' | 'condensed' List-level density inherited by StackedListItem rows that do not set their own density prop. Omit to let each row use its own default. A per-row density always overrides this list-level value. Note: when passing a variable that may be undefined, spread conditionally because exactOptionalPropertyTypes is enabled: {...(density ? { density } : {})}
children snippet req Row renderer. MUST render an <li> (the list root is a <ul role="list">). StackedListItem is the recommended row — it renders an <li> with leading/title/description/meta/trailing slots.
empty snippet Rendered when items is empty. The component automatically wraps the snippet output in <li class="cinder-data-list-empty">. Do NOT wrap in an <li> yourself — the component provides the <li> wrapper automatically. Pass only inner content (e.g. a <p>, a <div>, or plain text). Contrast with children, which must render an <li>.