HeroUI

TableNew

Tables display structured data in rows and columns with support for sorting, selection, column resizing, and infinite scrolling.

Import

import { Table } from '@heroui/react';

Usage

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
import {Table} from "@heroui/react";

export function Basic() {
  return (
    <Table>

Anatomy

Import the Table component and access all parts using dot notation.

import { Table } from '@heroui/react';

export default () => (
  <Table>
    <Table.ScrollContainer>
      <Table.Content aria-label="Example table">
        <Table.Header>
          <Table.Column>Name</Table.Column>
          <Table.Column>Role</Table.Column>
        </Table.Header>
        <Table.Body>
          <Table.Row>
            <Table.Cell>Kate Moore</Table.Cell>
            <Table.Cell>CEO</Table.Cell>
          </Table.Row>
        </Table.Body>
      </Table.Content>
    </Table.ScrollContainer>
    <Table.Footer>{/* Optional footer content */}</Table.Footer>
  </Table>
);

Secondary Variant

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
import {Table} from "@heroui/react";

export function SecondaryVariant() {
  return (
    <Table variant="secondary">

Sorting

Columns can be made sortable using the allowsSorting prop on Table.Column. Use sortDescriptor and onSortChange on Table.Content to manage sort state.

NameRoleStatusEmail
Emily DavisProduct ManagerInactiveemily@acme.com
John SmithCTOActivejohn@acme.com
Kate MooreCEOActivekate@acme.com
Michael BrownCFOActivemichael@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
"use client";

import type {SortDescriptor} from "@heroui/react";

import {Table, cn} from "@heroui/react";

Selection

Enable row selection with selectionMode on Table.Content. Use Checkbox with slot="selection" for select-all and per-row checkboxes.

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com

Selected: None

"use client";

import type {Selection} from "@heroui/react";

import {Checkbox, Table} from "@heroui/react";

Custom Cells

Worker IDMemberRoleStatusActions
#1234567
ED
Emily Davisemily@acme.com
Product ManagerInactive
#5273849
JS
John Smithjohn@acme.com
Chief Technology OfficerActive
#4586932
KM
Kate Moorekate@acme.com
Chief Executive OfficerActive
#8293746
MB
Michael Brownmichael@acme.com
Chief Financial OfficerActive
#7492836
SJ
Sara Johnsonsara@acme.com
Chief Marketing OfficerOn Leave
"use client";

import type {Selection, SortDescriptor} from "@heroui/react";

import {Avatar, Button, Checkbox, Chip, Table, cn} from "@heroui/react";

Pagination

Use Table.Footer to add a pagination component below the table.

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
"use client";

import {Pagination, Table} from "@heroui/react";
import {useMemo, useState} from "react";

Column Resizing

Wrap the table in Table.ResizableContainer and add Table.ColumnResizer inside each resizable column.

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
Emily DavisProduct ManagerInactiveemily@acme.com
import {Chip, Table} from "@heroui/react";

export function ColumnResizing() {
  return (
    <Table>

Empty State

Use renderEmptyState on Table.Body to display a custom message when the table has no data.

NameRoleStatusEmail
No results found
"use client";

import {EmptyState, Table} from "@heroui/react";
import {Icon} from "@iconify/react";

Async Loading

Use Table.LoadMore for infinite scrolling. It renders a sentinel row that triggers onLoadMore when scrolled into view.

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
Emily DavisProduct ManagerInactiveemily@acme.com
Davis WilsonLead DesignerActivedavis@acme.com
"use client";

import {Chip, Spinner, Table} from "@heroui/react";
import {useCallback, useRef, useState} from "react";

TanStack Table

HeroUI's Table works as a rendering layer on top of headless table libraries. This example uses TanStack Table for column definitions, sorting, and pagination — while HeroUI handles styling and accessibility.

NameRoleStatusEmail
Kate MooreCEOActivekate@acme.com
John SmithCTOActivejohn@acme.com
Sara JohnsonCMOOn Leavesara@acme.com
Michael BrownCFOActivemichael@acme.com
"use client";

import type {SortDescriptor} from "@heroui/react";
import type {SortingState} from "@tanstack/react-table";

Styling

Passing Tailwind CSS classes

You can customize individual Table parts:

import { Table } from '@heroui/react';

function CustomTable() {
  return (
    <Table className="border border-purple-200">
      <Table.ScrollContainer>
        <Table.Content aria-label="Custom styled table">
          <Table.Header className="bg-purple-50">
            <Table.Column>Name</Table.Column>
          </Table.Header>
          <Table.Body>
            <Table.Row className="hover:bg-purple-50">
              <Table.Cell>Kate Moore</Table.Cell>
            </Table.Row>
          </Table.Body>
        </Table.Content>
      </Table.ScrollContainer>
    </Table>
  );
}

Customizing the component classes

To customize the Table component classes, you can use the @layer components directive.
Learn more.

@layer components {
  .table-root {
    @apply relative grid w-full overflow-clip;
  }

  .table__header {
    @apply bg-gray-100;
  }

  .table__column {
    @apply px-4 py-2.5 text-left text-xs font-medium text-gray-600;
  }

  .table__row {
    @apply bg-white border-b border-gray-200;
  }

  .table__cell {
    @apply px-4 py-3 text-sm;
  }

  .table__footer {
    @apply flex items-center px-4 py-2.5;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Table component uses these CSS classes (View source styles):

Base Classes

  • .table-root - Root container (named table-root instead of table because table is a built-in Tailwind CSS utility class for display: table)
  • .table__scroll-container - Horizontal scroll wrapper with custom scrollbar
  • .table__content - The <table> element
  • .table__header - Header row (<thead>)
  • .table__column - Column header cell (<th>)
  • .table__body - Body section (<tbody>)
  • .table__row - Row element (<tr>)
  • .table__cell - Data cell (<td>)
  • .table__footer - Footer container (outside table)

Advanced Classes

  • .table__column-resizer - Drag handle for column resizing
  • .table__resizable-container - Wrapper enabling column resizing
  • .table__load-more - Sentinel row for infinite scrolling
  • .table__load-more-content - Styled container for the loading indicator

Variant Classes

  • .table-root--primary - Gray background container with card-style body (default)
  • .table-root--secondary - No background, standalone rounded headers

Interactive States

The Table supports both CSS pseudo-classes and data attributes for flexibility:

  • Hover: :hover or [data-hovered="true"] (row background change)
  • Selected: [data-selected="true"] (row highlight)
  • Focus: :focus-visible or [data-focus-visible="true"] (inset focus ring on rows, columns, and cells)
  • Disabled: :disabled or [aria-disabled="true"] (reduced opacity)
  • Sortable: [data-allows-sorting="true"] (interactive cursor on columns)
  • Dragging: [data-dragging="true"] (reduced opacity)
  • Drop Target: [data-drop-target="true"] (accent background)

API Reference

Table Props

PropTypeDefaultDescription
variant"primary" | "secondary""primary"Visual variant. Primary has a gray background container; secondary is flat with transparent rows.
classNamestring-Additional CSS classes for the root container
childrenReact.ReactNode-Table content (ScrollContainer, Footer, etc.)

Table.ScrollContainer Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReact.ReactNode-Table.Content element

Table.Content Props

Inherits from React Aria Table.

PropTypeDefaultDescription
aria-labelstring-Accessible label for the table
selectionMode"none" | "single" | "multiple""none"Selection behavior
selectedKeysSelection-Controlled selected keys
onSelectionChange(keys: Selection) => void-Selection change handler
sortDescriptorSortDescriptor-Current sort state
onSortChange(descriptor: SortDescriptor) => void-Sort change handler
classNamestring-Additional CSS classes

Table.Header Props

Inherits from React Aria TableHeader.

PropTypeDefaultDescription
columnsT[]-Dynamic column data for render prop pattern
childrenReact.ReactNode | (column: T) => React.ReactNode-Static columns or render prop

Table.Column Props

Inherits from React Aria Column.

PropTypeDefaultDescription
idstring-Column identifier
allowsSortingbooleanfalseWhether the column is sortable
isRowHeaderbooleanfalseWhether this column is a row header
defaultWidthstring | number-Default width for resizable columns
minWidthnumber-Minimum width for resizable columns
childrenReact.ReactNode | (values: ColumnRenderProps) => React.ReactNode-Column content or render prop with sort direction

Table.Body Props

Inherits from React Aria TableBody.

PropTypeDefaultDescription
itemsT[]-Dynamic row data for render prop pattern
renderEmptyState() => React.ReactNode-Content to display when the table is empty
childrenReact.ReactNode | (item: T) => React.ReactNode-Static rows or render prop

Table.Row Props

Inherits from React Aria Row.

PropTypeDefaultDescription
idstring | number-Row identifier
classNamestring-Additional CSS classes
childrenReact.ReactNode-Row cells

Table.Cell Props

Inherits from React Aria Cell.

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReact.ReactNode-Cell content

Table.Footer Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReact.ReactNode-Footer content (e.g., pagination)

Table.ColumnResizer Props

Inherits from React Aria ColumnResizer.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

Table.ResizableContainer Props

Inherits from React Aria ResizableTableContainer.

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReact.ReactNode-Table.Content element

Table.LoadMore Props

Inherits from React Aria TableLoadMoreItem.

PropTypeDefaultDescription
isLoadingbooleanfalseWhether data is currently loading
onLoadMore() => void-Handler called when the sentinel row is visible
childrenReact.ReactNode-Loading indicator content

Table.LoadMoreContent Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReact.ReactNode-Loading indicator content (e.g., Spinner)

Table.Collection Props

Re-exported from React Aria Collection. Used to render dynamic cells within rows alongside static cells (e.g., checkboxes).

PropTypeDefaultDescription
itemsT[]-Collection items
children(item: T) => React.ReactNode-Render prop for each item

On this page