Table

Table is a compound component for displaying structured data in rows and columns. It supports sorting, striped rows, sticky headers, and flexible data display.

3
Variants
3
Sizes
8
Sub-components
Pure
React

Playground

Preview
D
Status
PAY-7291Successemily@example.comDec 20, 2030$316.00
PAY-7292Successjames@example.comDec 20, 2030$242.00
PAY-7293Pendingsarah@example.comDec 21, 2030$837.00
PAY-7294Successdavid@example.comDec 21, 2030$124.00
PAY-7295Failedolivia@example.comDec 22, 2030$495.00
PAY-7296Successmichael@example.comDec 22, 2030$158.00
PAY-7297Pendingsophie@example.comDec 23, 2030$721.00
PAY-7298Successdaniel@example.comDec 24, 2030$89.00
PAY-7299Failedemma@example.comDec 24, 2030$362.00
PAY-7300Successryan@example.comDec 25, 2030$550.00
Variant
Size
Options
<Table>
  <Table.Header>
    <Table.Row>
      <Table.Head sortable sortDirection={sortKey === 'id' ? sortDir : null} onSort={() => handleSort('id')}>Invoice</Table.Head>
      <Table.Head>Status</Table.Head>
      <Table.Head sortable sortDirection={sortKey === 'email' ? sortDir : null} onSort={() => handleSort('email')}>Email</Table.Head>
      <Table.Head sortable sortDirection={sortKey === 'date' ? sortDir : null} onSort={() => handleSort('date')}>Date</Table.Head>
      <Table.Head align="right" sortable sortDirection={sortKey === 'amount' ? sortDir : null} onSort={() => handleSort('amount')}>Amount</Table.Head>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    {sortedData.map(row => (
      <Table.Row key={row.id} interactive>
        <Table.Cell className="font-mono font-normal">{row.id}</Table.Cell>
        <Table.Cell>
          <Badge
            variant="subtle"
            color={statusMap[row.status].color}
            size="sm"
          >
            {statusMap[row.status].label}
          </Badge>
        </Table.Cell>
        <Table.Cell className="text-text-muted">{row.email}</Table.Cell>
        <Table.Cell className="text-text-muted whitespace-nowrap">{row.date}</Table.Cell>
        <Table.Cell align="right" className="font-mono">${row.amount.toFixed(2)}</Table.Cell>
      </Table.Row>
    ))}
  </Table.Body>
</Table>

Variants

Default

NameRoleStatus
BobDesignerAway
AliceEngineerActive
<Table>
  <Table.Header>
    <Table.Row>
      <Table.Head>Name</Table.Head>
      <Table.Head>Role</Table.Head>
      <Table.Head>Status</Table.Head>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    <Table.Row>
      <Table.Cell>Bob</Table.Cell>
      <Table.Cell>Designer</Table.Cell>
      <Table.Cell>
        <Badge variant="subtle" color="warning" size="sm">Away</Badge>
      </Table.Cell>
    </Table.Row>
    <Table.Row>
      <Table.Cell>Alice</Table.Cell>
      <Table.Cell>Engineer</Table.Cell>
      <Table.Cell>
        <Badge variant="subtle" color="success" size="sm">Active</Badge>
      </Table.Cell>
    </Table.Row>
  </Table.Body>
</Table>

Bordered

NameRoleStatus
BobDesignerAway
AliceEngineerActive
<Table variant="bordered">...</Table>

Striped

NameRoleStatus
BobDesignerAway
AliceEngineerActive
CharliePMMeeting
DianaDevOpsActive
<Table variant="striped">...</Table>

Sizes

sm
Cell PY8px
Cell PX12px
Font14px
default
Cell PY12px
Cell PX16px
Font14px
lg
Cell PY16px
Cell PX24px
Font16px

API

Component Structure

Table— Pure React
.Header.Body.Footer.RowProps.HeadProps.CellProps.Caption

Props

Table

size"default"
"sm" | "default" | "lg"

Row density (sm: compact / default: standard / lg: spacious)

variant"default"
"default" | "bordered" | "striped"

Visual style of the table

stickyHeaderfalse
boolean

Fix header on scroll

wrapperClassNameundefined
string

className added to the scroll wrapper (e.g., "max-h-[400px]"). Use with stickyHeader

Table.Row

interactivefalse
boolean

Show highlight effect on hover

selectedfalse
boolean

Indicates row selected state (adds data-selected attribute)

Table.Head

align"left"
"left" | "center" | "right"

Horizontal text alignment

sortablefalse
boolean

Show sort indicator

sortDirectionnull
"asc" | "desc" | null

Current sort direction

onSortundefined
() => void

Callback on sort click

sortIconBuilt-in SVG
{ asc?: ReactNode, desc?: ReactNode, default?: ReactNode }

Customize sort icons (partial override supported)

Table.Cell

align"left"
"left" | "center" | "right"

Horizontal text alignment

Customization

sortIcon Customize sort icons freely via the sortIcon prop. Partial overrides are also supported.

Replace with Lucide icons

EmailRole
Bobbob@example.comDesigner
Alicealice@example.comEngineer
Charliecharlie@example.comPM
import { ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react' <Table.Head sortable sortIcon={{ asc: <ArrowUp className="icon-xs" />, desc: <ArrowDown className="icon-xs" />, default: <ArrowUpDown className="icon-xs" />, }} > Name </Table.Head>

Partial override

Grade
95A+
87B+
72C+
// Override only asc and desc (default keeps built-in icon) <Table.Head sortable sortIcon={{ asc: <span>↑</span>, desc: <span>↓</span> }}> Score </Table.Head>

Tip: Use icon-xs (14px) for sort icons — the ideal size for table header text.

Anatomy

1
2
3
Name
Status
4
5
Alice Johnson
Active
Bob Smith
Inactive
6
Showing 2 of 2 results
Cell PY12px
Cell PX16px
Head Font12px
1
Table
Root container
2
Header Row
Header row
3
Header Cell
Header cell
4
Body Row
Body row
5
Body Cell
Body cell
6
Footer
Footer row

Best Practices

Recommended

  • Use clear, descriptive header labels
  • Right-align numeric data
  • Use sticky headers for large data sets
  • Set a caption for accessibility

Don't

  • Don't create tables with too many columns
  • Don't use tables for layout purposes
  • Don't embed sort logic inside the component
  • Don't put overly complex content inside cells

Accessibility

Keyboard

TabMove focus between sort buttons
EnterTrigger sort

ARIA / WCAG

  • Uses semantic HTML (table/thead/tbody/th/td)
  • Sort direction announced via aria-sort
  • Sort icons use aria-hidden="true"
  • Table description supported via caption