Table

Table renders columns and rows data as a native table. It always wraps its <table> in a horizontal ScrollArea, so wide tables scroll instead of overflowing their layout. dividers, zebra, hover, and border are all opt-in.

import { Table } from "density-base-ui";

export default function TableExample() {
  return (
    <Table
      dividers
      columns={[
        { key: "name", header: "Name" },
        { key: "region", header: "Region" },
        { key: "status", header: "Status" },
      ]}
      rows={[
        { name: "api-gateway", region: "us-east-1", status: "Healthy" },
        { name: "auth-service", region: "us-east-1", status: "Healthy" },
        { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
      ]}
    />
  );
}

Row order follows the rows array, and each cell reads row[column.key]. Sorting and bulk row selection are not implemented yet.

Padding

padding adds a size-derived inset around the horizontal scroll area and defaults to false. cellPadding controls the dense, size-derived header and body cell inset and defaults to true. A row cell can instead be { content, padding } to enable or remove that cell’s inset; plain React node cell values remain supported.

import { Table, View } from "density-base-ui";

export default function TablePaddingExample() {
  return (
    <View>
      <Table
        border="border"
        padding
        cellPadding
        columns={[
          { key: "service", header: "Service" },
          { key: "status", header: "Status" },
        ]}
        rows={[
          {
            service: { content: "api-gateway", padding: false },
            status: "Healthy",
          },
          {
            service: "billing-worker",
            status: { content: "Degraded", padding: true },
          },
        ]}
      />
      <Table
        border="border"
        cellPadding
        columns={[
          { key: "service", header: "Service" },
          { key: "status", header: "Status" },
        ]}
        rows={[
          {
            service: { content: "api-gateway", padding: false },
            status: "Healthy",
          },
          {
            service: "billing-worker",
            status: { content: "Degraded", padding: true },
          },
        ]}
      />
      <Table
        border="border"
        padding
        columns={[
          { key: "service", header: "Service" },
          { key: "status", header: "Status" },
        ]}
        rows={[
          {
            service: { content: "api-gateway", padding: false },
            status: "Healthy",
          },
          {
            service: "billing-worker",
            status: { content: "Degraded", padding: true },
          },
        ]}
      />
      <Table
        border="border"
        columns={[
          { key: "service", header: "Service" },
          { key: "status", header: "Status" },
        ]}
        rows={[
          {
            service: { content: "api-gateway", padding: false },
            status: "Healthy",
          },
          {
            service: "billing-worker",
            status: { content: "Degraded", padding: true },
          },
        ]}
      />
    </View>
  );
}

Size

size scales header and body typography together.

import { Table, View } from "density-base-ui";

const columns = [
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
];

const rows = [
  { name: "api-gateway", region: "us-east-1", status: "Healthy" },
  { name: "auth-service", region: "us-east-1", status: "Healthy" },
  { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
];

export default function TableSizeExample() {
  return (
    <View>
      <Table size="sm" columns={columns} rows={rows} />
      <Table size="md" columns={columns} rows={rows} />
      <Table size="lg" columns={columns} rows={rows} />
    </View>
  );
}

Dividers

dividers adds a horizontal rule between rows.

import { Table } from "density-base-ui";

const columns = [
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
];

const rows = [
  { name: "api-gateway", region: "us-east-1", status: "Healthy" },
  { name: "auth-service", region: "us-east-1", status: "Healthy" },
  { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
];

export default function TableDividersExample() {
  return <Table dividers columns={columns} rows={rows} />;
}

Zebra

zebra alternates rows using the depth adjacent to the containing surface to help the eye track across wide rows. At depth 7, it uses depth 6 instead.

import { Table } from "density-base-ui";

const columns = [
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
];

const rows = [
  { name: "api-gateway", region: "us-east-1", status: "Healthy" },
  { name: "auth-service", region: "us-east-1", status: "Healthy" },
  { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
  { name: "cache-node", region: "us-west-2", status: "Offline" },
];

export default function TableZebraExample() {
  return <Table zebra columns={columns} rows={rows} />;
}

Hover

hover highlights a row’s background as the pointer moves over it. Hover over the table below to see it.

import { Table } from "density-base-ui";

const columns = [
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
];

const rows = [
  { name: "api-gateway", region: "us-east-1", status: "Healthy" },
  { name: "auth-service", region: "us-east-1", status: "Healthy" },
  { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
  { name: "cache-node", region: "us-west-2", status: "Offline" },
];

export default function TableHoverExample() {
  return <Table hover columns={columns} rows={rows} />;
}

Border

Set border="border" to draw the standard layout-safe outline around the table. Set border="none" or omit it for no outline.

import { Table } from "density-base-ui";

const columns = [
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
];

const rows = [
  { name: "api-gateway", region: "us-east-1", status: "Healthy" },
  { name: "auth-service", region: "us-east-1", status: "Healthy" },
  { name: "billing-worker", region: "eu-west-1", status: "Degraded" },
];

export default function TableBorderExample() {
  return <Table border="border" columns={columns} rows={rows} />;
}

Horizontal scrolling

Table always wraps its <table> in a horizontal ScrollArea. When columns outgrow the available width, the table scrolls instead of overflowing its layout. Set scrollbarVisibility="always" to keep the scrollbar visible instead of only showing it on hover, scrolling, or keyboard focus.

Default scrollbar (visible on hover)
Always-visible scrollbar
import { Label, Table, View } from "density-base-ui";

const columns = [
  { key: "id", header: "ID" },
  { key: "name", header: "Name" },
  { key: "region", header: "Region" },
  { key: "status", header: "Status" },
  { key: "cpu", header: "CPU" },
  { key: "memory", header: "Memory" },
  { key: "uptime", header: "Uptime" },
  { key: "owner", header: "Owner" },
  { key: "created", header: "Created" },
  { key: "tags", header: "Tags" },
];

const rows = [
  {
    id: "i-0a1b2c",
    name: "api-gateway",
    region: "us-east-1",
    status: "Healthy",
    cpu: "12%",
    memory: "1.2 GB",
    uptime: "42d",
    owner: "platform",
    created: "2026-01-04",
    tags: "prod, edge",
  },
  {
    id: "i-1d2e3f",
    name: "auth-service",
    region: "us-east-1",
    status: "Healthy",
    cpu: "8%",
    memory: "0.9 GB",
    uptime: "42d",
    owner: "platform",
    created: "2026-01-04",
    tags: "prod",
  },
  {
    id: "i-4a5b6c",
    name: "billing-worker",
    region: "eu-west-1",
    status: "Degraded",
    cpu: "63%",
    memory: "2.4 GB",
    uptime: "3d",
    owner: "billing",
    created: "2026-03-19",
    tags: "prod, batch",
  },
  {
    id: "i-7d8e9f",
    name: "cache-node",
    region: "us-west-2",
    status: "Offline",
    cpu: "0%",
    memory: "0 GB",
    uptime: "0d",
    owner: "platform",
    created: "2025-11-02",
    tags: "staging",
  },
];

export default function TableScrollExample() {
  return (
    <View align="start" gap="md" padding={false}>
      <View align="start" gap="xs" padding={false}>
        <Label as="div" emphasis="secondary" size="sm">
          Default scrollbar (visible on hover)
        </Label>
        <div style={{ maxWidth: "420px" }}>
          <Table columns={columns} rows={rows} />
        </div>
      </View>
      <View align="start" gap="xs" padding={false}>
        <Label as="div" emphasis="secondary" size="sm">
          Always-visible scrollbar
        </Label>
        <div style={{ maxWidth: "420px" }}>
          <Table scrollbarVisibility="always" columns={columns} rows={rows} />
        </div>
      </View>
    </View>
  );
}