Table

A responsive data table component with accessible markup. Built with native HTML <table> elements — no external dependencies.

A list of recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
import {
  Table,
  TableHeader,
  TableBody,
  TableRow,
  TableHead,
  TableCell,
  TableCaption,
} from "~/components/table";

export default function TableBasicDemo() {
  return (
    <Table>
      <TableCaption>A list of recent invoices.</TableCaption>
      <TableHeader>
        <TableRow>
          <TableHead>Invoice</TableHead>
          <TableHead>Status</TableHead>
          <TableHead>Method</TableHead>
          <TableHead class="text-right">Amount</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell class="font-medium">INV001</TableCell>
          <TableCell>Paid</TableCell>
          <TableCell>Credit Card</TableCell>
          <TableCell class="text-right">$250.00</TableCell>
        </TableRow>
        <TableRow>
          <TableCell class="font-medium">INV002</TableCell>
          <TableCell>Pending</TableCell>
          <TableCell>PayPal</TableCell>
          <TableCell class="text-right">$150.00</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Installation

CLI

Run the following command to add the component to your project:

npx @ark-preset/cli@latest add table

Manual

Create the recipe file at src/components/recipes/table.ts:

import { tv, type VariantProps } from "tailwind-variants";

export const tableVariants = tv({
  slots: {
    table: "w-full caption-bottom text-sm",
    header: "[&_tr]:border-b",
    body: "[&_tr:last-child]:border-0",
    row: "border-b border-muted transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
    head: "h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
    cell: "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
    caption: "mt-4 text-sm text-muted-foreground",
  },
});

export type TableVariants = VariantProps<typeof tableVariants>;

Create the component file at src/components/table/index.tsx:

import { splitProps, type Component } from "solid-js";
import { tableVariants } from "../recipes/table";
import { ark, type HTMLArkProps } from "@ark-ui/solid/factory";

const styles = tableVariants();

type TableProps = HTMLArkProps<"table">;
type TableHeaderProps = HTMLArkProps<"thead">;
type TableBodyProps = HTMLArkProps<"tbody">;
type TableRowProps = HTMLArkProps<"tr">;
type TableHeadProps = HTMLArkProps<"th">;
type TableCellProps = HTMLArkProps<"td">;
type TableCaptionProps = HTMLArkProps<"caption">;

const Table: Component<TableProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.table class={styles.table({ class: local.class })} {...others} />;
};

const TableHeader: Component<TableHeaderProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.thead class={styles.header({ class: local.class })} {...others} />;
};

const TableBody: Component<TableBodyProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.tbody class={styles.body({ class: local.class })} {...others} />;
};

const TableRow: Component<TableRowProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.tr class={styles.row({ class: local.class })} {...others} />;
};

const TableHead: Component<TableHeadProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.th class={styles.head({ class: local.class })} {...others} />;
};

const TableCell: Component<TableCellProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.td class={styles.cell({ class: local.class })} {...others} />;
};

const TableCaption: Component<TableCaptionProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.caption class={styles.caption({ class: local.class })} {...others} />;
};

export {
  Table,
  TableHeader,
  TableBody,
  TableRow,
  TableHead,
  TableCell,
  TableCaption,
  tableVariants,
};

Note: Make sure your project has the Tailwind CSS theme variables set up (--background, --foreground, --ring, --border, etc.) or override the utility classes to match your design system.

Usage

Basic Usage

A list of recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
import {
  Table,
  TableHeader,
  TableBody,
  TableRow,
  TableHead,
  TableCell,
  TableCaption,
} from "~/components/table";

export default function TableBasicDemo() {
  return (
    <Table>
      <TableCaption>A list of recent invoices.</TableCaption>
      <TableHeader>
        <TableRow>
          <TableHead>Invoice</TableHead>
          <TableHead>Status</TableHead>
          <TableHead>Method</TableHead>
          <TableHead class="text-right">Amount</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell class="font-medium">INV001</TableCell>
          <TableCell>Paid</TableCell>
          <TableCell>Credit Card</TableCell>
          <TableCell class="text-right">$250.00</TableCell>
        </TableRow>
        <TableRow>
          <TableCell class="font-medium">INV002</TableCell>
          <TableCell>Pending</TableCell>
          <TableCell>PayPal</TableCell>
          <TableCell class="text-right">$150.00</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Column alignment can be customized using the class prop:

<TableHead class="text-right">Amount</TableHead>
<TableCell class="text-right">$250.00</TableCell>

API Reference

ComponentPropTypeDefault
Tableclassstring
TableHeaderclassstring
TableBodyclassstring
TableRowclassstring
TableHeadclassstring
TableCellclassstring
TableCaptionclassstring

Anatomy

A table is composed of the following parts:

PartElementDescription
TabletableThe root table element.
TableHeadertheadThe header row group.
TableBodytbodyThe body row group.
TableRowtrA table row.
TableHeadthA header cell.
TableCelltdA data cell.
TableCaptioncaptionA table caption.