GitHub
Core
Glass
Brutal
Humanist

Table
Pro

Tables display data in rows and columns with support for sorting, row selection, pagination, and infinite scroll. The modular structure allows flexible composition of headers, cells, toolbars, and pagination.

Table Playground

Table Playground
Preview
Code
Tasks50
Task Name
Project
Due Date
Assignees
Progress
Status
User Personas
Pinterest
Jan 13, 2025
+1
15%
In-progress
Visual Inspiration
Facebook
Jan 14, 2025
100%
In-review
Brand Guide Deck
Google Ads
Jan 15, 2025
45%
Overdue
Setting Style Guide
Slack Team
Jan 16, 2025
72%
Finished
User Research
Figma Design
Jan 17, 2025
88%
In-progress
UI Design Module 1
GitHub Repo
Jan 18, 2025
30%
In-review
Information Architecture
Salesforce CRM
Jan 19, 2025
60%
Overdue
Market Research
Jira Project
Jan 20, 2025
+1
100%
Finished
Data Synthesis
Pinterest
Jan 21, 2025
5%
In-progress
Wireframes
Facebook
Jan 22, 2025
95%
In-review
Page 1/5
Controls
Density:
Default
Compact
Loading:
Pagination
Infinite Scroll
Toolbar:

Installation

You can add the table component to your project manually:

1

Install the following dependencies:

npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/button @react-aria/focus @react-aria/interactions @react-aria/progress @react-aria/utils
2

Copy and paste the following code into your project.

Loading...
3

Update the import paths to match your project setup.

Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.

Basic Usage

A simple table with header and data rows:

<Table>
  <TableHeader>
    <TableRow>
      <TableHeaderCell>Name</TableHeaderCell>
      <TableHeaderCell>Email</TableHeaderCell>
      <TableHeaderCell>Role</TableHeaderCell>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableRowCell>John Doe</TableRowCell>
      <TableRowCell>john@example.com</TableRowCell>
      <TableRowCell>Admin</TableRowCell>
    </TableRow>
  </TableBody>
</Table>

Density

Two density options are available — default (56px rows) and compact (48px rows):

<Table density="default">...</Table>
<Table density="compact">...</Table>

Sorting

Enable sorting on columns with sortable prop and handle sort state:

const [sortColumn, setSortColumn] = useState<string | null>(null);
const [sortDirection, setSortDirection] = useState<'asc' | 'desc' | null>(null);
const handleSort = (column: string) => {
  if (sortColumn === column) {
    if (sortDirection === 'asc') setSortDirection('desc');
    else if (sortDirection === 'desc') { setSortColumn(null); setSortDirection(null); }
    else setSortDirection('asc');
  } else {
    setSortColumn(column);
    setSortDirection('asc');
  }
};
<Table sortColumn={sortColumn} sortDirection={sortDirection} onSort={handleSort}>
  <TableHeader>
    <TableRow>
      <TableHeaderCell columnKey="name" sortable>Name</TableHeaderCell>
      <TableHeaderCell columnKey="email" sortable>Email</TableHeaderCell>
    </TableRow>
  </TableHeader>
  ...
</Table>

Row Selection

Enable row selection with checkboxes:

const [selectedIds, setSelectedIds] = useState<string[]>([]);
<Table
  selectedIds={selectedIds}
  onSelectionChange={setSelectedIds}
  allRowIds={data.map(r => r.id)}
>
  <TableHeader>
    <TableRow>
      <TableHeaderCell type="checkbox" />
      <TableHeaderCell>Name</TableHeaderCell>
    </TableRow>
  </TableHeader>
  <TableBody>
    {data.map(row => (
      <TableRow key={row.id} rowId={row.id}>
        <TableRowCell type="checkbox" />
        <TableRowCell>{row.name}</TableRowCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

Toolbar

Add a toolbar with title, search, filters, and action button:

<TableToolbar
  title="Users"
  count={100}
  showSearch
  searchValue={searchValue}
  onSearchChange={setSearchValue}
  showFilters
  onFilterClick={() => console.log('Filters clicked')}
  showButton
  buttonText="Add User"
  onButtonClick={() => console.log('Add clicked')}
/>

Pagination

Add pagination controls below the table:

<Pagination
  currentPage={1}
  totalItems={100}
  pageSize={10}
  onPageChange={(page) => console.log('Page:', page)}
  onPageSizeChange={(size) => console.log('Size:', size)}
  pageSizeOptions={[10, 25, 50, 100]}
/>

Infinite Scroll

Enable infinite scroll with the loadingStrategy prop:

<Table loadingStrategy="infinite">
  <TableBody
    hasMore={hasMore}
    loadingMore={isLoading}
    onLoadMore={loadMoreData}
  >
    {data.map(row => (
      <TableRow key={row.id}>...</TableRow>
    ))}
  </TableBody>
</Table>

Keep the header visible when scrolling:

<div style={{ maxHeight: 400 }}>
  <Table stickyHeader>
    ...
  </Table>
</div>

Accessibility

The Table components are fully accessible:

  • Keyboard navigation: Tab through interactive cells, Enter/Space to toggle selection
  • Screen readers: Proper role="grid" with column headers and row structure
  • Sort announcements: Sort direction announced via aria-sort
  • Selection state: Checkbox states properly announced

Table Props

PropTypeDefaultDescription
density'default' | 'compact''default'Row height density.
selectedIdsstring[][]Array of selected row IDs.
onSelectionChange(ids: string[]) => voidCallback when selection changes.
sortColumnstring | nullnullCurrently sorted column key.
sortDirection'asc' | 'desc' | nullnullCurrent sort direction.
onSort(column: string, direction: ...) => voidCallback when sort changes.
loadingbooleanfalseLoading state.
loadingStrategy'pagination' | 'infinite''pagination'Loading strategy.
stickyHeaderbooleanfalseKeep header visible when scrolling.
standalonebooleanfalseAdd border/radius when used without wrapper.
allRowIdsstring[][]All row IDs for select-all functionality.

TableHeaderCell Props

PropTypeDefaultDescription
type'text' | 'checkbox''text'Cell type.
columnKeystringColumn key for sorting.
sortablebooleanfalseEnable sorting on this column.
align'left' | 'center' | 'right''left'Text alignment.
widthnumber | stringColumn width.
minWidthnumber | stringMinimum column width.

TableRowCell Props

PropTypeDefaultDescription
type'text' | 'checkbox''text'Cell type.
align'left' | 'center' | 'right''left'Text alignment.
truncatebooleanfalseTruncate long text with ellipsis.

TableToolbar Props

PropTypeDefaultDescription
titlestring'Items'Toolbar title.
countnumberItem count to display in badge.
showTitleBadgebooleantrueShow count badge.
showSearchbooleantrueShow search input.
searchPlaceholderstring'Search task, project...'Search placeholder.
searchValuestringControlled search value.
onSearchChange(value: string) => voidSearch change callback.
showFiltersbooleantrueShow filter button.
onFilterClick() => voidFilter button callback.
showButtonbooleantrueShow action button.
buttonTextstring'Add Task'Action button text.
onButtonClick() => voidAction button callback.
actionsReactNodeCustom actions slot.

Pagination Props

PropTypeDefaultDescription
currentPagenumber1Current page number.
totalItemsnumber0Total number of items.
pageSizenumber10Items per page.
onPageChange(page: number) => voidPage change callback.
onPageSizeChange(size: number) => voidPage size change callback.
pageSizeOptionsnumber[][10, 25, 50, 100]Available page sizes.

On this page