Data Display

Table

Composite root that establishes table semantics, density, and sort context for nested header, body, row, and cell parts.

import { Table } from '@lostgradient/cinder/table';
tablegrid
01

Overview

Full data table with header, body, and optional footer for structured tabular content.

Usage

Table is a compound component. Import the parent and compose its leaves via the namespace API: Table.Header, Table.HeaderCell, Table.Body, Table.Row, and Table.Cell.

svelte
<script lang="ts">
  import { Table } from '@lostgradient/cinder/table';

  const people = [
    { name: 'Ada Lovelace', role: 'Mathematician', commits: 142 },
    { name: 'Grace Hopper', role: 'Computer Scientist', commits: 98 },
  ];
</script>

<Table scrollable caption="Recent contributors">
  <Table.Header>
    <Table.Row>
      <Table.HeaderCell>Name</Table.HeaderCell>
      <Table.HeaderCell>Role</Table.HeaderCell>
      <Table.HeaderCell align="right">Commits</Table.HeaderCell>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    {#each people as person (person.name)}
      <Table.Row>
        <Table.Cell>{person.name}</Table.Cell>
        <Table.Cell>{person.role}</Table.Cell>
        <Table.Cell align="right">{person.commits}</Table.Cell>
      </Table.Row>
    {/each}
  </Table.Body>
</Table>

Pass scrollable for dense or unknown-width tables. The Table root stays a native <table>; Cinder generates a focusable .cinder-table-scroll wrapper that owns horizontal overflow when the available component width is too narrow. Use scrollContainerProps to label, style, or override attributes on that generated wrapper. When scrollable and stickyHeader are combined, the generated wrapper is the sticky header's scroll container; set a bounded block size on scrollContainerProps when the table should scroll vertically inside that wrapper.

The leaves remain importable individually for à-la-carte builds — see @lostgradient/cinder/table-body, @lostgradient/cinder/table-cell, @lostgradient/cinder/table-header, @lostgradient/cinder/table-header-cell, and @lostgradient/cinder/table-row.

Live preview
02

When to use

Use when
  • Comparing rows of structured records across consistent columns.
  • Coordinating column sort state across header cells via the sort prop.
Avoid when
  • Rendering a responsive card grid — use grid-list instead.
  • Listing key-value attributes of one entity — use description-list instead.
03

Examples

Scrollable table

Hand-composed cells inside the public horizontal scroll wrapper for dense tables.

Empty table

A table with no body rows still renders the header and caption.

Selectable rows

Table with a select-all checkbox in the header and per-row selection. One row is explicitly disabled from selection.

Sticky sortable header

Sortable columns with stickyHeader={true}. Scroll the table body to verify the focus ring on the sort button is not clipped by the sticky thead.

04

Props

Props for table
Name Type Default Required Bindable Description
sort TableSort | undefined bind Bound sort state. When the user activates a sortable header, this prop is updated to reflect the new column / direction. Pass undefined initially when no column is sorted; the component will never write back undefined itself (sort always toggles to a column).
caption text Visual caption rendered as a <caption> element.
stickyHeader boolean false When true, the header sticks to the top of the scrolling container.
density 'comfortable' | 'condensed' | 'spacious' 'comfortable' Vertical padding density for header and body cells. Defaults to 'comfortable'.
selectable boolean false Enables the leading selection column on the entire table. When true: - The single TableRow inside TableHeader renders a leading <th> with a select-all checkbox sourced from the header's props. - Every TableRow inside TableBody renders a leading selection cell. Selection is strictly controlled — the consumer owns all selection state.
scrollable boolean false When true, wraps the table in a .cinder-table-scroll container that enables horizontal overflow scrolling for dense or unknown-width tables. Use this instead of manually wrapping Table in .cinder-table-scroll. When combined with stickyHeader, the generated wrapper is the sticky header's scroll container. Set a bounded block size on scrollContainerProps when the table should scroll vertically inside that wrapper.
scrollContainerProps Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'class' > & { /** Additional class names merged with `.cinder-table-scroll`. */ class?: string; } Attributes forwarded to the generated .cinder-table-scroll wrapper when scrollable is true. The wrapper is focusable by default so keyboard users can scroll read-only wide tables. When the table has a caption, or when aria-label or aria-labelledby is provided here, the wrapper becomes a named region; pass role or tabindex here to override those defaults.
children snippet req TableHeader, TableBody, etc.