---
title: Table
description: A powerful and flexible table component for displaying tabular data with sorting, filtering, and pagination capabilities.
category: Data Display
related: [Pagination, Title, Container, Button, Dialog]
commonPatterns: [table-with-pagination, table-with-filters, table-with-actions]
---

Source: https://clickhouse.design/click-ui/table

# Table

A powerful and flexible table component for displaying tabular data with sorting, filtering, and pagination capabilities.

## Quick start

```tsx
import { Table, Container, Title } from '@clickhouse/click-ui'

function MyTable() {
const headers = [
  { label: 'Name' },
  { label: 'Email' },
  { label: 'Role' },
]

const rows = [
  {
    id: 1,
    items: [
      { label: 'John Doe' },
      { label: 'john@example.com' },
      { label: 'Admin' },
    ],
  },
  {
    id: 2,
    items: [
      { label: 'Jane Smith' },
      { label: 'jane@example.com' },
      { label: 'User' },
    ],
  },
]

return (
  <Container orientation='vertical' gap='md'>
    <Title size='lg'>Users</Title>
    <Table headers={headers} rows={rows} />
  </Container>
)
}
```

## Example

## Props

| Prop          | Type                                                                                 | Default value | Description                                                                                 |
| ------------- | ------------------------------------------------------------------------------------ | ------------- | ------------------------------------------------------------------------------------------- |
| headers \*    | `Array<TableHeaderType>`                                                             | `[]`          | Array of header definitions. Each header must have a label property. Required.              |
| rows \*       | `Array<TableRowType>`                                                                | `[]`          | Array of row data. Each row must have an id and items array. Required.                      |
| isSelectable  | `boolean`                                                                            | `false`       | Whether rows can be selected with checkboxes                                                |
| selectedIds   | `Array<number \| string>`                                                            | `[]`          | Array of selected row IDs. Used with isSelectable.                                          |
| onSelect      | `(selectedItems: Array<{index: number, item: TableRowType}>) => void`                | `undefined`   | Callback when rows are selected. Receives array of selected items with index and item data. |
| onDelete      | `(item: TableRowType, index: number) => void`                                        | `undefined`   | Callback when delete action is triggered on a row                                           |
| onEdit        | `(item: TableRowType, index: number) => void`                                        | `undefined`   | Callback when edit action is triggered on a row                                             |
| onSort        | `(direction: 'asc' \| 'desc', header: TableHeaderType, headerIndex: number) => void` | `undefined`   | Callback when a column header is clicked for sorting                                        |
| loading       | `boolean`                                                                            | `false`       | Whether the table is in a loading state. Shows loading indicator.                           |
| noDataMessage | `ReactNode`                                                                          | `undefined`   | Custom message to display when table has no data                                            |
| size          | `"sm" \| "md"`                                                                       | `"sm"`        | Size variant of the table cells                                                             |
| showHeader    | `boolean`                                                                            | `true`        | Whether to show the table header row                                                        |
| rowHeight     | `string`                                                                             | `undefined`   | Custom height for table rows (e.g., "40px")                                                 |

```tsx
import { Table } from '@clickhouse/click-ui'

function UserTable() {
const headers = [
  { label: 'Name' },
  { label: 'Email' },
  { label: 'Role' },
]

const rows = [
  {
    id: 1,
    items: [
      { label: 'John Doe' },
      { label: 'john@example.com' },
      { label: 'Admin' },
    ],
  },
  {
    id: 2,
    items: [
      { label: 'Jane Smith' },
      { label: 'jane@example.com' },
      { label: 'User' },
    ],
  },
]

return <Table headers={headers} rows={rows} />
}
```

## Type definitions

### TableHeaderType

```tsx
interface TableHeaderType {
label: ReactNode // The header text or content
isSortable?: boolean // Whether the column can be sorted
sortDir?: 'asc' | 'desc' // Current sort direction
sortPosition?: 'left' | 'right' // Position of sort icon
width?: string // Column width (e.g., "200px")
overflowMode?: 'truncated' | 'truncate-middle' | 'wrap' // How cell text overflows (default: truncated)
resizable?: boolean // Whether the column can be resized (not compatible with overflowMode: 'wrap')
}
```

### TableRowType

```tsx
interface TableRowType {
id: number | string // Unique identifier for the row (required)
items: Array<{
  label: ReactNode // Cell content (required)
  overflowMode?: 'truncated' | 'truncate-middle' | 'wrap' // Overrides the header overflowMode for this cell
}> // Array of cell content (required)
isActive?: boolean // Whether the row is in active state
isDeleted?: boolean // Whether the row is marked as deleted
isIndeterminate?: boolean // For checkbox indeterminate state
}
```

## Related components

- **Pagination**: Use with Table for paginated data navigation
- **Title**: Use above Table for page headers
- **Container**: Use to layout Table with other components
- **Button**: Use for table actions (edit, delete, etc.)
- **Dialog**: Use for edit/create forms related to table data

## Common use cases

### Basic data display

```tsx
import { Table } from '@clickhouse/click-ui'

const headers = [
{ label: 'Product' },
{ label: 'Price' },
{ label: 'Stock' },
]

const rows = [
{
  id: 1,
  items: [
    { label: 'Widget A' },
    { label: '$19.99' },
    { label: '50' },
  ],
},
]

<Table headers={headers} rows={rows} />
```

### With sorting

```tsx
import { Table } from '@clickhouse/click-ui'
import { useState } from 'react'

function SortableTable() {
const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')

const headers = [
  { 
    label: 'Name',
    isSortable: true,
    sortDir: sortDir,
  },
  { label: 'Email' },
]

const handleSort = (direction: 'asc' | 'desc') => {
  setSortDir(direction)
  // Implement your sorting logic
}

return (
  <Table
    headers={headers}
    rows={rows}
    onSort={handleSort}
  />
)
}
```

### With row selection

```tsx
import { Table } from '@clickhouse/click-ui'
import { useState } from 'react'

function SelectableTable() {
const [selectedIds, setSelectedIds] = useState<Array<number | string>>([])

const handleSelect = (selectedItems: Array<{index: number, item: any}>) => {
  const ids = selectedItems.map(item => item.item.id)
  setSelectedIds(ids)
}

return (
  <Table
    headers={headers}
    rows={rows}
    isSelectable={true}
    selectedIds={selectedIds}
    onSelect={handleSelect}
  />
)
}
```

### With actions (edit/delete)

```tsx
import { Table } from '@clickhouse/click-ui'

function TableWithActions() {
const handleEdit = (item: any, index: number) => {
  console.log('Edit item:', item)
}

const handleDelete = (item: any, index: number) => {
  console.log('Delete item:', item)
}

return (
  <Table
    headers={headers}
    rows={rows}
    onEdit={handleEdit}
    onDelete={handleDelete}
  />
)
}
```

### Text overflow

Control how long cell content is displayed using `overflowMode` on a header (applies to the whole column) or on an individual cell in `row.items`.

- **`truncated`** (default): Cuts text at the end with an ellipsis
- **`truncate-middle`**: Cuts text in the middle, showing the start and end
- **`wrap`**: Breaks text across multiple lines

`overflowMode: 'wrap'` does not work with resizable columns. Use truncation modes instead when `resizable` is enabled.

```tsx
import { Table } from '@clickhouse/click-ui'

const headers = [
{ label: 'Year', width: '80px' },
{ label: 'Milestone', overflowMode: 'wrap' },
]

const rows = [
{
  id: '2021',
  items: [
    { label: '2021' },
    {
      label:
        'ClickHouse, Inc. incorporates in Delaware. Initial $50M investment from Index Ventures and Benchmark Capital.',
    },
  ],
},
]

<Table headers={headers} rows={rows} />
```

## See also

- Common Patterns - See Table with Pagination example
- Pagination - For paginated tables
