loom muslin

Table

Compound native table: Table.Header, Table.Body, Table.Row, Table.Head, Table.Cell.

Previewlive — edit controls below
InvoiceStatusAmount
INV-2041Paid$1,240.00
INV-2040Pending$860.50

Appearance

State

Basic

import { Table } from "@loom/muslin-react";

<Table>
  <Table.Header>
    <Table.Row>
      <Table.Head>Invoice</Table.Head>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    <Table.Row>
      <Table.Cell>INV-1</Table.Cell>
    </Table.Row>
  </Table.Body>
</Table>

Status column

Compound table with badges and right-aligned numbers.

import { Badge, Table } from "@loom/muslin-react";

<Table>
  <Table.Header>
    <Table.Row>
      <Table.Head>Invoice</Table.Head>
      <Table.Head>Status</Table.Head>
      <Table.Head>Amount</Table.Head>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    {rows.map((row) => (
      <Table.Row key={row.id}>
        <Table.Cell className="font-mono">{row.id}</Table.Cell>
        <Table.Cell><Badge variant={row.status}>{row.label}</Badge></Table.Cell>
        <Table.Cell className="text-right tabular-nums">{row.amount}</Table.Cell>
      </Table.Row>
    ))}
  </Table.Body>
</Table>

Sortable, selectable, empty

Sort headers drive state; checkbox column selects; empty renders the EmptyState row.

import { Checkbox, Table } from "@loom/muslin-react";

<Table density="compact">
  <Table.Header>
    <Table.Row>
      <Table.Head onSort={() => toggle("invoice")} sort={dir}>Invoice</Table.Head>
      <Table.Head>Status</Table.Head>
    </Table.Row>
  </Table.Header>
  {rows.length === 0 ? (
    <Table.Body empty={{ title: "No invoices yet", description: "Adjust the filters or create one.", colSpan: 2 }} />
  ) : (
    rows.map((row) => (
      <Table.Body key={row.id}>
        <Table.Row selected={row.selected}>
          <Table.Cell><Checkbox checked={row.selected} onChange={() => toggle(row.id)} aria-label={row.id} /></Table.Cell>
          <Table.Cell>{row.id}</Table.Cell>
        </Table.Row>
      </Table.Body>
    ))
  )}
</Table>