Table
A real table, styled and made to scroll on narrow screens. Compound down to the cell, so the consumer decides what goes in each one.
API
Props
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "table" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Table.Head
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "thead" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Table.Body
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "tbody" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Table.Row
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "tr" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Table.HeadCell
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "th" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Table.Cell
| prop | type | default | |
|---|---|---|---|
as? | ElementType | "td" | the element or component to render |
className? | string | — | merged over the defaults, so it wins |
…rest | props of as | — | typed against the chosen element |
Examples
Usage
<Table>
<Table.Head>
<Table.Row>
<Table.HeadCell>prop</Table.HeadCell>
<Table.HeadCell>type</Table.HeadCell>
<Table.HeadCell>default</Table.HeadCell>
</Table.Row>
</Table.Head>
<Table.Body>
<Table.Row>
<Table.Cell>active</Table.Cell>
<Table.Cell>boolean</Table.Cell>
<Table.Cell>false</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>as</Table.Cell>
<Table.Cell>ElementType</Table.Cell>
<Table.Cell>"div"</Table.Cell>
</Table.Row>
</Table.Body>
</Table>| prop | type | default |
|---|---|---|
| active | boolean | false |
| as | ElementType | "div" |
Details
Compound down to the cell
The kit could have taken columns and rows as data and rendered the markup for you. It does not, because the moment one cell needs a chip, a link or a second line, a data-driven table either grows a render prop per column or stops being usable. Here the cells are yours from the start.
Mapping is therefore explicit, and pairs naturally with List — an empty array renders an empty body rather than a broken table.
<Table.Body>
<List
array={rows}
itemExtractor={({ row }) => (
<Table.Row key={row.id}>
<Table.Cell>{row.name}</Table.Cell>
</Table.Row>
)}
/>
</Table.Body>Cells do not wrap
Cells are whitespace-nowrap by default. A table that wraps its cells turns into a block of ragged text at the first narrow column, and the row loses the alignment that made it a table. When a column is genuinely prose — a description, a message — opt that one back into wrapping.
<Table.Cell className="whitespace-normal">{row.description}</Table.Cell>It stays a table
Each part renders its real element — table, thead, tbody, tr, th, td — rather than divs with a grid. Screen readers announce row and column positions, the browser handles headers, and none of that has to be reimplemented with aria attributes.