Shadcn Table for React and Tailwind
A responsive table component.
| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | [email protected] | Admin | active |
| Bruno Silva | [email protected] | Editor | invited |
| Clara Mendes | [email protected] | Viewer | inactive |
| David Park | [email protected] | Editor | active |
Installation
bunx --bun shadcn@latest add https://kit.dev/r/table.jsonpnpm dlx shadcn@latest add https://kit.dev/r/table.jsonnpx shadcn@latest add https://kit.dev/r/table.jsonyarn shadcn@latest add https://kit.dev/r/table.jsonInstall the following dependencies:
bun add @ark-ui/reactpnpm add @ark-ui/reactnpm install @ark-ui/reactyarn add @ark-ui/reactCopy and paste the following code into your project.
"use client";
import { ark } from "@ark-ui/react/factory";
import type React from "react";
import { cn } from "@/lib/utils";
interface TableProps extends React.ComponentProps<typeof ark.table> {
/**
* Whether the table rows are hoverable.
*
* @default true
*/
isHoverable?: boolean;
/**
* The variant of the table.
*
* @default "plain"
*/
variant?: "plain" | "striped";
}
export const Table = (props: TableProps) => {
const { variant = "plain", isHoverable = true, className, ...rest } = props;
return (
<div className="relative w-full overflow-auto" data-slot="table-wrapper">
<ark.table
className={cn(
"group/table",
"w-full",
"caption-bottom",
"text-foreground text-sm",
className
)}
data-hoverable={isHoverable}
data-slot="table"
data-variant={variant}
{...rest}
/>
</div>
);
};
export const TableHeader = (props: React.ComponentProps<typeof ark.thead>) => {
const { className, ...rest } = props;
return (
<ark.thead
className={cn("[&_tr]:border-b", className)}
data-slot="table-header"
{...rest}
/>
);
};
export interface TableBodyProps
extends React.ComponentProps<typeof ark.tbody> {}
export const TableBody = (props: TableBodyProps) => {
const { className, ...rest } = props;
return (
<ark.tbody
className={cn("[&_tr:last-child]:border-0", className)}
data-slot="table-body"
{...rest}
/>
);
};
export const TableFooter = (props: React.ComponentProps<typeof ark.tfoot>) => {
const { className, ...rest } = props;
return (
<ark.tfoot
className={cn(
"border-t",
"bg-muted/48",
"font-medium",
"last:[&>tr]:border-b-0",
className
)}
data-slot="table-footer"
{...rest}
/>
);
};
export const TableRow = (props: React.ComponentProps<typeof ark.tr>) => {
const { className, ...rest } = props;
return (
<ark.tr
className={cn(
"border-b",
"data-[state=selected]:bg-muted",
"group-data-[variant=striped]/table:even:bg-muted/30",
"group-data-[hoverable=true]/table:[&:has(td):hover]:bg-muted/48",
className
)}
data-slot="table-row"
{...rest}
/>
);
};
export const TableHead = (props: React.ComponentProps<typeof ark.th>) => {
const { className, ...rest } = props;
return (
<ark.th
className={cn(
"h-10 px-2",
"text-left align-middle",
"font-medium text-muted-foreground",
"rtl:text-right",
"has-[[role=checkbox]]:ps-2 has-[[role=checkbox]]:pe-0",
className
)}
data-slot="table-head"
{...rest}
/>
);
};
export const TableCell = (props: React.ComponentProps<typeof ark.td>) => {
const { className, ...rest } = props;
return (
<ark.td
className={cn(
"whitespace-nowrap p-2 align-middle",
"has-[[role=checkbox]]:ps-2 has-[[role=checkbox]]:pe-0",
className
)}
data-slot="table-cell"
{...rest}
/>
);
};
export const TableCaption = (
props: React.ComponentProps<typeof ark.caption>
) => {
const { className, ...rest } = props;
return (
<ark.caption
className={cn("mt-4", "text-muted-foreground text-sm", className)}
data-slot="table-caption"
{...rest}
/>
);
};Update the import paths to match your project setup.
Anatomy
Table
├── TableCaption
├── TableHeader
│ └── TableRow
│ └── TableHead
├── TableBody
│ └── TableRow
│ └── TableCell
└── TableFooter
└── TableRow
└── TableCellUsage
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
TableFooter,
} from "@/components/ui/table";<Table>
<TableCaption />
<TableHeader>
<TableRow>
<TableHead />
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell />
<TableCell />
</TableRow>
</TableBody>
<TableFooter />
</Table>Accessibility
Always use a TableCaption to help assistive technologies announce what the table represents.
Use with the sr-only class to make the caption screen-reader only if you don't want to show it.
<Table>
<TableCaption className="sr-only">
Monthly revenue by product.
</TableCaption>
{/* ... */}
</Table>Examples
Striped
Use variant="striped" on Table for alternating row backgrounds.
With footer
Use TableFooter for summary rows, totals, or notes.
With actions
Add an actions column with buttons per row.
With action bar
Use checkboxes for row selection and an action bar that appears when one or more rows are selected. See the action bar component.
With context menu
Wrap each row with ContextMenuTrigger so right-clicking shows a context menu with row actions.
Disable row hover
Set isHoverable={false} on Table to disable the hover background on body rows.
API Reference
Table
Scrollable wrapper around a native table. Supports striped and hover variants.
| Prop | Type | Default |
|---|---|---|
variant | "plain" | "striped" | "plain" |
isHoverable | boolean | true |
className | string | - |
asChild | boolean | false |
TableHeader
Table header row group.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableBody
Table body row group.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableFooter
Table footer row group for totals or summary rows.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableRow
A single table row.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableHead
Header cell for column titles.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableCell
Data cell for body or footer rows.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |
TableCaption
Accessible caption describing the table. Use sr-only for screen-reader only.
| Prop | Type | Default |
|---|---|---|
className | string | - |
asChild | boolean | false |