Table
Tables display structured data in rows and columns with support for sorting, selection, column resizing, and infinite scrolling.
Usage
import { Table } from '@hareui/vue'<script setup lang="ts">import type { TableColumn, TableRow } from '@hareui/vue'import { Table } from '@hareui/vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' }, { key: 'email', label: 'Email' },]const rows: TableRow[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', email: '[email protected]' },]</script><template> <Table aria-label="Team members" :columns="columns" :rows="rows" :ui="{ content: 'min-w-[600px]' }" /></template>Anatomy
HeroUI composes Table.ScrollContainer, Table.Content, Table.Header, Table.Column, Table.Body, Table.Row and Table.Cell. HareUI renders the same <table> structure from two arrays: columns (one entry per header) and rows (one object per row, looked up as row[column.key]). Per-column slots replace the default header or cell content.
<Table aria-label="Team members" :columns="columns" :rows="rows">
<template #status-header="{ column, sortDirection }" /> <!-- optional: header content for the `status` column -->
<template #status-cell="{ row, value }" /> <!-- optional: cell content for the `status` column -->
<template #empty /> <!-- optional: shown when `rows` is empty -->
<template #load-more /> <!-- optional: shown while `loading` (defaults to a Spinner) -->
<template #footer /> <!-- optional: below the table, e.g. pagination -->
</Table>ui keys: base, scrollContainer, resizableContainer, content, header, column, sortableColumnHeader, sortableColumnIndicator, body, row, cell, footer, columnResizer, loadMore, loadMoreContent.
Examples
Secondary Variant
<script setup lang="ts">import type { TableColumn, TableRow } from '@hareui/vue'import { Table } from '@hareui/vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' }, { key: 'email', label: 'Email' },]const rows: TableRow[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', email: '[email protected]' },]</script><template> <Table aria-label="Team members" variant="secondary" :columns="columns" :rows="rows" :ui="{ content: 'min-w-[600px]' }" /></template>Async Loading
Set has-more to render a sentinel row that emits loadMore when scrolled into view. While loading is true, the #load-more row is shown.
<script setup lang="ts">import type { TableColumn } from '@hareui/vue'import { Chip, Table } from '@hareui/vue'import { computed, ref } from 'vue'const statusColorMap = { 'Active': 'success', 'Inactive': 'danger', 'On Leave': 'warning' } as consttype Status = keyof typeof statusColorMapconst allUsers: { id: number, name: string, role: string, status: Status, email: string }[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', email: '[email protected]' }, { id: 5, name: 'Emily Davis', role: 'Product Manager', status: 'Inactive', email: '[email protected]' }, { id: 6, name: 'Davis Wilson', role: 'Lead Designer', status: 'Active', email: '[email protected]' }, { id: 7, name: 'Olivia Martinez', role: 'Frontend Engineer', status: 'Active', email: '[email protected]' }, { id: 8, name: 'James Taylor', role: 'Backend Engineer', status: 'Active', email: '[email protected]' }, { id: 9, name: 'Sophia Anderson', role: 'QA Engineer', status: 'On Leave', email: '[email protected]' }, { id: 10, name: 'Liam Thomas', role: 'DevOps Engineer', status: 'Active', email: '[email protected]' }, { id: 11, name: 'Lucas Martinez', role: 'Product Manager', status: 'Active', email: '[email protected]' }, { id: 12, name: 'Emma Johnson', role: 'Frontend Engineer', status: 'Active', email: '[email protected]' }, { id: 13, name: 'Noah Davis', role: 'Backend Engineer', status: 'Active', email: '[email protected]' }, { id: 14, name: 'Ava Wilson', role: 'Lead Designer', status: 'Active', email: '[email protected]' }, { id: 15, name: 'Oliver Martinez', role: 'Frontend Engineer', status: 'Active', email: '[email protected]' }, { id: 16, name: 'Isabella Johnson', role: 'Backend Engineer', status: 'Active', email: '[email protected]' }, { id: 17, name: 'Mia Davis', role: 'Lead Designer', status: 'Active', email: '[email protected]' }, { id: 18, name: 'William Wilson', role: 'Frontend Engineer', status: 'Active', email: '[email protected]' },]const ITEMS_PER_PAGE = 6const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' }, { key: 'email', label: 'Email' },]const items = ref(allUsers.slice(0, ITEMS_PER_PAGE))const loading = ref(false)const hasMore = computed(() => items.value.length < allUsers.length)function loadMore() { if (!hasMore.value || loading.value) return loading.value = true setTimeout(() => { items.value = allUsers.slice(0, items.value.length + ITEMS_PER_PAGE) loading.value = false }, 1500)}</script><template> <Table aria-label="Async loading table" :columns="columns" :has-more="hasMore" :loading="loading" :rows="items" :ui="{ scrollContainer: 'h-[280px] overflow-y-auto', content: 'min-w-[600px]', header: 'sticky top-0 z-10 bg-surface-secondary', }" @load-more="loadMore" > <template #status-cell="{ row }"> <Chip :color="statusColorMap[row.status as Status]" size="sm" variant="soft">{{ row.status }}</Chip> </template> </Table></template>Sorting
Set sortable on a column to render the sort indicator and make the header toggle the sort. Bind v-model:sort-descriptor and pass rows already sorted: the table displays the sort state, it does not sort the data.
<script setup lang="ts">import type { TableColumn, TableSortDescriptor } from '@hareui/vue'import { Table } from '@hareui/vue'import { computed, ref } from 'vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true, sortable: true }, { key: 'role', label: 'Role', sortable: true }, { key: 'status', label: 'Status', sortable: true }, { key: 'email', label: 'Email', sortable: true },]const users = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', email: '[email protected]' }, { id: 5, name: 'Emily Davis', role: 'Product Manager', status: 'Inactive', email: '[email protected]' },]const sortDescriptor = ref<TableSortDescriptor>({ column: 'name', direction: 'ascending' })const rows = computed(() => { const { column, direction } = sortDescriptor.value const sorted = [...users].sort((a, b) => String(a[column as keyof typeof a]).localeCompare(String(b[column as keyof typeof b]))) return direction === 'descending' ? sorted.reverse() : sorted})</script><template> <Table v-model:sort-descriptor="sortDescriptor" aria-label="Table with sorting" :columns="columns" :rows="rows" :ui="{ content: 'min-w-[600px]' }" /></template>Selection
Enable row selection with selection-mode. The table adds a checkbox column with a select-all checkbox in the header; bind v-model:selected-keys to read or control the selection ('all' or a Set of row ids).
Selected: None
<script setup lang="ts">import type { TableColumn, TableRow, TableSelection } from '@hareui/vue'import { Table } from '@hareui/vue'import { ref } from 'vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' }, { key: 'email', label: 'Email' },]const rows: TableRow[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', email: '[email protected]' },]const selectedKeys = ref<TableSelection>(new Set())</script><template> <div class="flex flex-col gap-3"> <Table v-model:selected-keys="selectedKeys" aria-label="Table with selection" :columns="columns" :rows="rows" selection-mode="multiple" :ui="{ content: 'min-w-[600px]' }" /> <p class="text-sm text-muted"> Selected: <span class="font-medium">{{ selectedKeys === 'all' ? 'All' : selectedKeys.size > 0 ? [...selectedKeys].join(', ') : 'None' }}</span> </p> </div></template>Expandable Rows
Rows with children are nested. Use tree-column to designate the column that is indented by depth, and render a toggle in that column's cell slot with the toggle, isExpanded and hasChildItems slot props. Use v-model:expanded-keys to control which rows are expanded.
<script setup lang="ts">import type { TableColumn, TableRow, TableSelection } from '@hareui/vue'import { Button, Table } from '@hareui/vue'import { Icon } from '@iconify/vue'import { ref } from 'vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'type', label: 'Type' }, { key: 'date', label: 'Date Modified' },]const rows: TableRow[] = [ { id: '1', name: 'Documents', type: 'Directory', date: '10/20/2025', children: [ { id: '2', name: 'Project', type: 'Directory', date: '8/2/2025', children: [ { id: '3', name: 'Weekly Report', type: 'File', date: '7/10/2025' }, { id: '4', name: 'Budget', type: 'File', date: '8/20/2025' }, ], }, ], }, { id: '5', name: 'Photos', type: 'Directory', date: '2/3/2026', children: [ { id: '6', name: 'Image 1', type: 'File', date: '1/23/2026' }, { id: '7', name: 'Image 2', type: 'File', date: '2/3/2026' }, ], },]const expandedKeys = ref<TableSelection>(new Set(['1']))</script><template> <Table v-model:expanded-keys="expandedKeys" aria-label="Files" :columns="columns" :rows="rows" tree-column="name" :ui="{ content: 'min-w-[520px]' }" > <template #name-cell="{ row, hasChildItems, isExpanded, toggle }"> <span class="flex items-center gap-1"> <Button v-if="hasChildItems" aria-label="Toggle row" icon-only size="sm" variant="ghost" @click="toggle"> <Icon aria-hidden="true" :class="['size-4 text-muted transition-transform duration-150', isExpanded ? 'rotate-90' : 'rtl:rotate-180']" icon="gravity-ui:chevron-right" /> </Button> <span>{{ row.name }}</span> </span> </template> </Table></template>Column Resizing
Set resizable on a column to add a column resizer to its header. As with HeroUI's ResizableContainer, the columns of a resizable table share the container's width: width sets each column's initial size (pixels, '25%' or '2fr', default '1fr'), clamped by minWidth (default 75) and maxWidth. Resizing a column fixes the columns to its left at their current width.
<script setup lang="ts">import type { TableColumn, TableRow } from '@hareui/vue'import { Chip, Table } from '@hareui/vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true, minWidth: 160, resizable: true }, { key: 'role', label: 'Role', minWidth: 220, resizable: true }, { key: 'status', label: 'Status', minWidth: 100, resizable: true }, { key: 'email', label: 'Email', minWidth: 200 },]const rows: TableRow[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active', color: 'success', email: '[email protected]' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active', color: 'success', email: '[email protected]' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On Leave', color: 'warning', email: '[email protected]' }, { id: 4, name: 'Michael Brown', role: 'CFO', status: 'Active', color: 'success', email: '[email protected]' }, { id: 5, name: 'Emily Davis', role: 'Product Manager', status: 'Inactive', color: 'danger', email: '[email protected]' },]</script><template> <Table aria-label="Table with resizable columns" :columns="columns" :rows="rows" :ui="{ content: 'min-w-[700px]' }"> <template #status-cell="{ row }"> <Chip :color="row.color" size="sm" variant="soft">{{ row.status }}</Chip> </template> </Table></template>Empty State
Use the #empty slot to display a custom message when the table has no data.
<script setup lang="ts">import type { TableColumn } from '@hareui/vue'import { EmptyState, Table } from '@hareui/vue'import { Icon } from '@iconify/vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' }, { key: 'email', label: 'Email' },]</script><template> <Table aria-label="Empty table" class="min-h-[200px]" :columns="columns" :rows="[]" :ui="{ content: 'h-full min-w-[600px]' }"> <template #empty> <EmptyState class="flex h-full w-full flex-col items-center justify-center gap-4 text-center"> <Icon class="size-6 text-muted" icon="gravity-ui:tray" /> <span class="text-sm text-muted">No results found</span> </EmptyState> </template> </Table></template>Custom Cells
<script setup lang="ts">import type { TableColumn, TableSelection, TableSortDescriptor } from '@hareui/vue'import { Avatar, Button, Chip, Table } from '@hareui/vue'import { Icon } from '@iconify/vue'import { computed, ref } from 'vue'const statusColorMap = { 'Active': 'success', 'Inactive': 'danger', 'On Leave': 'warning' } as consttype Status = keyof typeof statusColorMapconst AVATARS = 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars'const users: { id: number, name: string, image_url: string, role: string, status: Status, email: string }[] = [ { id: 4586932, name: 'Kate Moore', image_url: `${AVATARS}/red.jpg`, role: 'Chief Executive Officer', status: 'Active', email: '[email protected]' }, { id: 5273849, name: 'John Smith', image_url: `${AVATARS}/green.jpg`, role: 'Chief Technology Officer', status: 'Active', email: '[email protected]' }, { id: 7492836, name: 'Sara Johnson', image_url: `${AVATARS}/blue.jpg`, role: 'Chief Marketing Officer', status: 'On Leave', email: '[email protected]' }, { id: 8293746, name: 'Michael Brown', image_url: `${AVATARS}/purple.jpg`, role: 'Chief Financial Officer', status: 'Active', email: '[email protected]' }, { id: 1234567, name: 'Emily Davis', image_url: `${AVATARS}/orange.jpg`, role: 'Product Manager', status: 'Inactive', email: '[email protected]' },]const columns: TableColumn[] = [ { key: 'id', label: 'Worker ID', isRowHeader: true, sortable: true, class: 'after:hidden' }, { key: 'name', label: 'Member', sortable: true }, { key: 'role', label: 'Role', sortable: true, class: 'min-w-52' }, { key: 'status', label: 'Status', sortable: true, class: 'min-w-25' }, { key: 'actions', label: 'Actions' },]const selectedKeys = ref<TableSelection>(new Set())const sortDescriptor = ref<TableSortDescriptor>({ column: 'name', direction: 'ascending' })const rows = computed(() => { const { column, direction } = sortDescriptor.value return [...users].sort((a, b) => { const cmp = String(a[column as keyof typeof a]).localeCompare(String(b[column as keyof typeof b])) return direction === 'descending' ? -cmp : cmp })})const initials = (name: string) => name.split(' ').map(n => n[0]).join('')</script><template> <Table v-model:selected-keys="selectedKeys" v-model:sort-descriptor="sortDescriptor" aria-label="Table with custom cells" :columns="columns" :rows="rows" selection-mode="multiple" :ui="{ content: 'min-w-[800px]' }" > <template #actions-header> <span class="block text-end">Actions</span> </template> <template #id-cell="{ row }"> <div class="flex items-center gap-2 font-medium"> #{{ row.id }} <Button :aria-label="`Copy ID #${row.id}`" icon-only size="sm" variant="ghost"> <Icon class="size-4 text-muted" icon="gravity-ui:copy" /> </Button> </div> </template> <template #name-cell="{ row }"> <div class="flex items-center gap-3"> <Avatar :fallback="initials(row.name)" size="sm" :src="row.image_url" /> <div class="flex flex-col"> <span class="text-xs">{{ row.name }}</span> <span class="text-xs text-muted">{{ row.email }}</span> </div> </div> </template> <template #status-cell="{ row }"> <Chip :color="statusColorMap[row.status as Status]" size="sm" variant="soft">{{ row.status }}</Chip> </template> <template #actions-cell="{ row }"> <div class="flex items-center gap-1"> <Button :aria-label="`View ${row.name}`" icon-only size="sm" variant="tertiary"> <Icon class="size-4" icon="gravity-ui:eye" /> </Button> <Button :aria-label="`Edit ${row.name}`" icon-only size="sm" variant="tertiary"> <Icon class="size-4" icon="gravity-ui:pencil" /> </Button> <Button :aria-label="`Delete ${row.name}`" icon-only size="sm" variant="danger-soft"> <Icon class="size-4" icon="gravity-ui:trash-bin" /> </Button> </div> </template> </Table></template>Customization
Tailwind CSS
Use the class prop for the root, ui for every part, and column.class for one column's header and cells:
<script setup lang="ts">import type { TableColumn, TableRow } from '@hareui/vue'import { Table } from '@hareui/vue'const columns: TableColumn[] = [ { key: 'name', label: 'Name', isRowHeader: true }, { key: 'role', label: 'Role' }, { key: 'status', label: 'Status' },]const rows: TableRow[] = [ { id: 1, name: 'Kate Moore', role: 'CEO', status: 'Active' }, { id: 2, name: 'John Smith', role: 'CTO', status: 'Active' }, { id: 3, name: 'Sara Johnson', role: 'CMO', status: 'On leave' },]</script><template> <Table aria-label="Team members" class="w-full max-w-2xl overflow-hidden rounded-xl border border-border/80 shadow-sm ring-1 ring-black/5 dark:ring-white/10" :columns="columns" :rows="rows" :ui="{ content: 'min-w-[600px]', header: 'bg-neutral-100/80 dark:bg-neutral-800/80', column: 'text-xs font-semibold uppercase tracking-wide text-neutral-500 dark:text-neutral-400', row: 'border-t border-border/60 transition-colors hover:bg-neutral-100/60 even:bg-neutral-50/50 dark:hover:bg-neutral-800/50 dark:even:bg-neutral-900/30', }" > <template #name-cell="{ value }"> <span class="font-medium text-neutral-900 dark:text-neutral-100">{{ value }}</span> </template> </Table></template>Global theme override
Override the table theme app-wide with createHareUI:
app.use(createHareUI({
ui: {
table: {
slots: {
header: 'bg-gray-100',
column: 'px-4 py-2.5 text-left text-xs font-medium text-gray-600',
row: 'border-b border-gray-200',
cell: 'bg-white px-4 py-3 text-sm',
},
},
},
}))Styling Reference
Each rendered element carries the same data-slot string as HeroUI, so selectors translate 1:1.
ui key | data-slot | Description |
|---|---|---|
base | table | Root container |
scrollContainer | table-scroll-container | Horizontal scroll wrapper |
resizableContainer | table-resizable-container | Scroll wrapper used when a column is resizable |
content | table-content | The <table> element |
header | table-header | The <thead> element |
column | table-column | Header cell |
sortableColumnHeader | table-sortable-column-header | Label and indicator of a sortable column |
sortableColumnIndicator | table-sortable-column-indicator | Sort direction chevron |
body | table-body | The <tbody> element |
row | table-row | Body row |
cell | table-cell | Body cell |
columnResizer | table-column-resizer | Column resize handle |
loadMore | table-load-more | Row shown while loading more |
loadMoreContent | table-load-more-content | Content wrapper of the load-more row |
footer | table-footer | Footer below the table |
HeroUI's modifier classes correspond to props (HareUI renders utilities, not BEM classes, so style through class, ui or createHareUI):
variant:primary(default, rows on a secondary surface),secondary(.table-root--{variant})
Interactive States
- Hover:
:hover(row background change) - Selected:
[data-selected="true"](row highlight) - Focus:
:focus-visible(inset focus ring on rows and sortable columns) - Disabled:
[aria-disabled="true"](reduced opacity) - Sortable:
[data-allows-sorting="true"](interactive cursor on columns)
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | TableColumn[] | - | Column definitions, in display order. |
rows | TableRow[] | - | Row data, already sorted by the caller according to sortDescriptor (Table only displays the sort indicator and emits changes). |
ariaLabel | string | - | Accessible label for the table. |
variant | "primary" | "secondary" | "primary" | Visual variant. Primary has a gray background container with a card-style body; secondary is flat with transparent rows. |
selectionMode | "multiple" | "single" | "none" | "none" | Row selection behavior. Adds a checkbox column when not 'none'. |
defaultSelectedKeys | TableSelection | new Set() | Selected row keys when uncontrolled. |
disabledKeys | TableSelectionKey[] | - | Row keys excluded from selection, in addition to any row with disabled. |
defaultSortDescriptor | TableSortDescriptor | - | Sort state when uncontrolled. |
treeColumn | string | - | Key of the column that renders indentation for nested rows and receives tree-related slot props. |
defaultExpandedKeys | TableSelection | new Set() | Expanded row keys when uncontrolled. |
hasMore | boolean | false | Adds the load-more sentinel at the end of the body; loadMore is emitted when it scrolls into view. |
loading | boolean | false | Shows the #load-more row (a Spinner by default) and stops re-emitting loadMore while the sentinel stays visible. |
ui | ComponentSlots<{ slots: { base: string; scrollContainer: string; resizableContainer: string; content: string; header: string; column: string[]; sortableColumnHeader: string; sortableColumnIndicator: string; body: string; row: string[]; cell: string[]; footer: string; columnResizer: string[]; loadMore: string; loadMoreContent: string; }; variants: { variant: { primary: { base: string; content: string; body: string[]; }; secondary: { header: string; column: string; body: string; row: string; cell: string; }; }; }; defaultVariants: { variant: string; }; }> | - | Per-slot class overrides. |
selectedKeys | TableSelection | - | Controlled selected row keys. Use v-model:selected-keys. |
expandedKeys | TableSelection | - | Controlled expanded row keys (tree rows). Use v-model:expanded-keys. |
sortDescriptor | TableSortDescriptor | - | Controlled sort state. Use v-model:sort-descriptor. |
Slots
| Slot | Props | Description |
|---|---|---|
empty | any | Content shown instead of the body when rows is empty. |
load-more | any | Content of the load-more row shown while loading. Defaults to a Spinner. |
footer | any | Footer content, rendered outside the scrollable table (e.g. pagination). |
Emits
| Event | Payload | Description |
|---|---|---|
loadMore | [] | - |
update:selectedKeys | [value: TableSelection | undefined] | - |
update:expandedKeys | [value: TableSelection | undefined] | - |
update:sortDescriptor | [value: TableSortDescriptor | undefined] | - |
TableColumn
| Prop | Type | Description |
|---|---|---|
key | string | Unique column key, looked up as row[key] |
label | string | Header text |
sortable | boolean | Shows the sort indicator; clicking the header updates sortDescriptor |
isRowHeader | boolean | Renders this column's cells as row headers (role="rowheader") |
align | 'start' | 'center' | 'end' | Text alignment of the header and cells |
width | number | '${number}%' | '${number}fr' | Initial width; percentages and fr apply to resizable tables only |
minWidth / maxWidth | number | Width limits in px for resizable tables (minWidth defaults to 75) |
resizable | boolean | Adds a column resizer |
class | any | Classes for this column's header and cells |
TableRow
| Prop | Type | Description |
|---|---|---|
id | string | number | Row key used by selection and expansion (defaults to the row index) |
children | TableRow[] | Nested rows (with tree-column) |
disabled | boolean | Excludes the row from selection |