Skip to content
BigBang

Popular

    ↑↓Navigate↵OpenEscClose
    TR

    Components

    Table

    Shows small, read-only data in a semantic HTML table.

    Storybook
    Storybook
    Source
    Source

    The example below loads live from Storybook; open it in Storybook for the controls.

    Live example, StorybookOpen in Storybook

    A Table has a caption (caption), a header row and data rows. The caption names the table. Use Table.RowHeader for the first cell that names the row.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function Default() {
    return (
    <Table caption="Item list">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Third item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    density sets the row height: compact is at least 32 px, standard (the default) 40 px, comfortable 48 px. Use compact for long tables that users scan.

    Item list: compact
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Item list: comfortable
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    import { Badge, Table } from '@bigbang/ui';
    export default function Density() {
    return (
    <div className="flex flex-col gap-3xl">
    {(['compact', 'comfortable'] as const).map((density) => (
    <Table key={density} caption={`Item list: ${density}`} density={density}>
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    ))}
    </div>
    );
    }

    striped tints every second body row. It helps the eye follow a row across a wide table. Header and footer rows are not tinted.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function Striped() {
    return (
    <Table caption="Item list" striped>
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Third item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    numeric aligns the cell to the end and uses tabular numerals, so digits line up. Give the column header the same prop. Use align="center" for short statuses.

    Item list
    NameCountStatus
    First item1,240Active
    Second item86Draft
    import { Table } from '@bigbang/ui';
    export default function Numeric() {
    return (
    <Table caption="Item list">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell align="center">Status</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell align="center">Active</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell align="center">Draft</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    Table.Footer is for summary rows such as totals; it takes the header colour.

    Item list
    NameCount
    First item1,240
    Second item86
    Total1,326
    import { Table } from '@bigbang/ui';
    export default function WithFooter() {
    return (
    <Table caption="Item list">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell numeric>1,240</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell numeric>86</Table.Cell>
    </Table.Row>
    </Table.Body>
    <Table.Footer>
    <Table.Row>
    <Table.RowHeader>Total</Table.RowHeader>
    <Table.Cell numeric>1,326</Table.Cell>
    </Table.Row>
    </Table.Footer>
    </Table>
    );
    }

    selected tints the row with the selected background and adds data-selected. A plain table has no aria-selected; the selection is a visual state. Say it in text too when the meaning matters.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function Selected() {
    return (
    <Table caption="Item list">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row selected>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Third item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    hoverable tints a body row on hover; it is on by default, and hoverable={false} turns it off for a table that only shows a few values. Only the colour changes; the row never lifts. For a clickable row use DataTable, not this component.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function Hoverable() {
    return (
    <Table caption="Item list" hoverable>
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Third item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    stickyHeader keeps the header cells at the top while the body scrolls. Give the container a height with className, such as max-h-64.

    Item list
    NameStatusCreatedCountOwner
    Item 1Active12 Oct 20261,240Alex
    Item 2Draft14 Oct 202686Sam
    Item 3Pending15 Oct 2026305Jo
    Item 4Active12 Oct 20261,240Alex
    Item 5Draft14 Oct 202686Sam
    Item 6Pending15 Oct 2026305Jo
    Item 7Active12 Oct 20261,240Alex
    Item 8Draft14 Oct 202686Sam
    Item 9Pending15 Oct 2026305Jo
    Item 10Active12 Oct 20261,240Alex
    Item 11Draft14 Oct 202686Sam
    Item 12Pending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function StickyHeader() {
    return (
    <Table caption="Item list" stickyHeader className="max-h-64">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>Item 1</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 2</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 3</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 4</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 5</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 6</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 7</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 8</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 9</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 10</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 11</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Item 12</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    When the table is wider than its container, the container scrolls sideways. The scroll region is named and takes keyboard focus; Tab to it and scroll with the arrow keys. Cut long text with truncate and a column width.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    import { Badge, Table } from '@bigbang/ui';
    export default function HorizontalScroll() {
    return (
    <Table caption="Item list" className="max-w-md">
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }

    Table takes its colours from surface, text and border tokens; it keeps the same structure in both modes.

    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    Item list
    NameStatusCreatedCountOwner
    First itemActive12 Oct 20261,240Alex
    Second itemDraft14 Oct 202686Sam
    Third itemPending15 Oct 2026305Jo
    import { Badge, Table } from '@bigbang/ui';
    export default function Striped() {
    return (
    <Table caption="Item list" striped>
    <Table.Header>
    <Table.Row>
    <Table.HeaderCell>Name</Table.HeaderCell>
    <Table.HeaderCell>Status</Table.HeaderCell>
    <Table.HeaderCell>Created</Table.HeaderCell>
    <Table.HeaderCell numeric>Count</Table.HeaderCell>
    <Table.HeaderCell>Owner</Table.HeaderCell>
    </Table.Row>
    </Table.Header>
    <Table.Body>
    <Table.Row>
    <Table.RowHeader>First item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="success">Active</Badge>
    </Table.Cell>
    <Table.Cell>12 Oct 2026</Table.Cell>
    <Table.Cell numeric>1,240</Table.Cell>
    <Table.Cell>Alex</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Second item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="neutral">Draft</Badge>
    </Table.Cell>
    <Table.Cell>14 Oct 2026</Table.Cell>
    <Table.Cell numeric>86</Table.Cell>
    <Table.Cell>Sam</Table.Cell>
    </Table.Row>
    <Table.Row>
    <Table.RowHeader>Third item</Table.RowHeader>
    <Table.Cell>
    <Badge tone="warning">Pending</Badge>
    </Table.Cell>
    <Table.Cell>15 Oct 2026</Table.Cell>
    <Table.Cell numeric>305</Table.Cell>
    <Table.Cell>Jo</Table.Cell>
    </Table.Row>
    </Table.Body>
    </Table>
    );
    }