Glin UI
Primitive / Moleculebeta

Table

Composable data table with semantic sections and glass variant support.

Edit on GitHub
ClientStatusAmountActions
INV-2041Due Oct 02
NSNorthwind Studio
Paid$1,240.00
INV-2040Due Oct 14
FLFabrikam Labs
Pending$3,890.00
INV-2039Due Sep 21
CHContoso Health
Overdue$620.50
INV-2038Due Sep 18
TTTailspin Toys
Paid$2,115.00

Installation

Install from
pnpm dlx @glinui/cli@latest add table

Prefer the package?

Usage

Variants

Every vocabulary variant on the default tone. Omit variant to follow the ambient design style.

NameStatus
Glin UIActive
NameStatus
Glin UIActive
NameStatus
Glin UIActive
NameStatus
Glin UIActive
NameStatus
Glin UIActive
NameStatus
Glin UIActive
NameStatus
Glin UIActive
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@glinui/ui"
export function TableVariantsDemo() {
return (
<div className="grid gap-4 md:grid-cols-2">
<Table variant="glinr" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="solid" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="plain" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="soft" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="outline" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="ghost" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
<Table variant="gradient" containerClassName="w-full"><TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader><TableBody><TableRow><TableCell>Glin UI</TableCell><TableCell>Active</TableCell></TableRow></TableBody></Table>
</div>
)
}

In a layout

A striped compact table inside a card with an export action and pagination.

Projects

Traffic over the last 30 days.

ProjectOwnerStatusVisits
Glin UIMaya KovacsLive48,210
DocsJonas OkaforLive21,904
RegistryPriya NairBuilding9,318
PlaygroundDiego AlvarezPaused2,044
Showing 1 to 4 of 12
import { CaretLeft, CaretRight, Download } from "@phosphor-icons/react"
import {
Badge,
Button,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from "@glinui/ui"
export function Demo() {
const rows = [
{ name: "Glin UI", owner: "Maya Kovacs", visits: "48,210", status: "Live" },
{ name: "Docs", owner: "Jonas Okafor", visits: "21,904", status: "Live" },
{ name: "Registry", owner: "Priya Nair", visits: "9,318", status: "Building" },
{ name: "Playground", owner: "Diego Alvarez", visits: "2,044", status: "Paused" }
]
const tone = { Live: "success", Building: "warning", Paused: "neutral" } as const
return (
<Card className="w-full max-w-3xl">
<CardHeader>
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<CardTitle>Projects</CardTitle>
<CardDescription>Traffic over the last 30 days.</CardDescription>
</div>
<Button size="sm" variant="outline">
<Download aria-hidden className="size-4" />
Export
</Button>
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<Table striped size="sm">
<TableHeader>
<TableRow>
<TableHead>Project</TableHead>
<TableHead>Owner</TableHead>
<TableHead>Status</TableHead>
<TableHead align="right">Visits</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rows.map((row) => (
<TableRow key={row.name}>
<TableCell className="font-medium">{row.name}</TableCell>
<TableCell>{row.owner}</TableCell>
<TableCell><Badge variant="soft" tone={tone[row.status as keyof typeof tone]}>{row.status}</Badge></TableCell>
<TableCell align="right" className="tabular-nums">{row.visits}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div className="flex items-center justify-between gap-3 text-sm text-[var(--color-muted)]">
<span>Showing 1 to 4 of 12</span>
<div className="flex items-center gap-2">
<Button size="sm" variant="outline" disabled aria-label="Previous page"><CaretLeft aria-hidden className="size-4" /></Button>
<Button size="sm" variant="outline" aria-label="Next page"><CaretRight aria-hidden className="size-4" /></Button>
</div>
</div>
</CardContent>
</Card>
)
}

When to choose Table vs DataTable

- Use `Table` for invoices, comparison matrices, read-only reports, and layouts where you control every row and cell. - Use `DataTable` for operational data views where users need filtering, sorting, pagination, and row selection with minimal setup.

Glass Variant

import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell, TableCaption } from "@glinui/ui"

export function TableGlassDemo() {
  return (
    <Table variant="glass" grid>
      <TableCaption>Quarterly metrics</TableCaption>
      <TableHeader>
        <TableRow>
          <TableHead>Metric</TableHead>
          <TableHead align="right">Value</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Conversion</TableCell>
          <TableCell align="right">7.3%</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  )
}

Lift table with YesNo cells

variant lift turns the overflow wrapper into a lift surface. wide sets a minimum width so it scrolls on small screens.

import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, YesNo } from "@glinui/ui"

export function Demo() {
  return (
    <Table variant="lift" wide interactive={false}>
      <TableHeader>
        <TableRow>
          <TableHead>Feature</TableHead>
          <TableHead align="center">Us</TableHead>
          <TableHead align="center">Them</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Self-host</TableCell>
          <TableCell align="center"><YesNo value /></TableCell>
          <TableCell align="center"><YesNo value={false} /></TableCell>
        </TableRow>
      </TableBody>
    </Table>
  )
}

Accessibility

  • Native `<table>` semantics with proper `<thead>`/`<tbody>` structure.
  • Use `<th>` for column headers.
  • Sticky headers preserve semantics because structure remains native.
  • Uses semantic table elements (`table`, `thead`, `tbody`, `th`, `td`, `caption`).
  • Keep column headers descriptive for screen reader table navigation.
  • Use `TableCaption` to provide context when needed.

ARIA Attributes

  • Native table semantics with `<th scope>`

Reduced Motion

Row hover color transitions use motion-safe classes with reduced-motion fallback.

Row hover transitions respect reduced-motion preferences.

Affected properties

background-color

API Reference

Table

PropTypeRequiredDefaultDescription
variant"glinr" | "solid" | "plain" | "soft" | "outline" | "ghost" | "gradient" | "glass" | "liquid" | "matte" | "lift"-ambient (glinr)Surface variant. Omit to follow the ambient design style (glinr by default, plain for minimal, glass for glass).
size"sm" | "md" | "lg"-mdText and spacing scale.
stickyHeaderboolean-falseMakes `<TableHeader />` stick to the top while scrolling.
stickyFirstColumnboolean-falsePins the first column while horizontally scrolling.
stripedboolean-falseApplies alternating row background treatment.
interactiveboolean-trueEnables row hover treatment.
gridboolean-falseAdds vertical grid separators between cells.
layout"auto" | "fixed"-autoSets table layout algorithm.
noWrapboolean-falseForces single-line cell and header content.
rowDividersboolean-trueToggles horizontal row borders.
containerClassNamestring--Class names for the scroll container wrapper.
align"left" | "center" | "right"No"left"Auto-generated from TypeScript source.
stickybooleanNofalseAuto-generated from TypeScript source.
truncatebooleanNofalseAuto-generated from TypeScript source.

TableHeader

PropTypeRequiredDefaultDescription
classNamestring--Additional class names.
align"left" | "center" | "right"No"left"Auto-generated from TypeScript source.
stickybooleanNofalseAuto-generated from TypeScript source.
truncatebooleanNofalseAuto-generated from TypeScript source.

TableRow

PropTypeRequiredDefaultDescription
tone"default" | "info" | "success" | "warning" | "danger"-defaultApplies semantic row emphasis.
classNamestring--Additional class names.
align"left" | "center" | "right"No"left"Auto-generated from TypeScript source.
stickybooleanNofalseAuto-generated from TypeScript source.
truncatebooleanNofalseAuto-generated from TypeScript source.

TableHead

PropTypeRequiredDefaultDescription
align"left" | "center" | "right"NoleftText alignment for header cells.
stickybooleanNofalsePins a specific header cell to the left.
classNamestring--Additional class names.
truncatebooleanNofalseAuto-generated from TypeScript source.

TableBody

PropTypeRequiredDefaultDescription
classNamestring--Additional class names.
align"left" | "center" | "right"No"left"Auto-generated from TypeScript source.
stickybooleanNofalseAuto-generated from TypeScript source.
truncatebooleanNofalseAuto-generated from TypeScript source.

TableCell

PropTypeRequiredDefaultDescription
align"left" | "center" | "right"NoleftText alignment for body cells.
truncatebooleanNofalseApplies single-line truncation with ellipsis.
stickybooleanNofalsePins a specific body cell to the left.
classNamestring--Additional class names.

Source

Import directly from the package or browse the source on GitHub. Click any file to view it.

Import

import { Table } from "@glinui/ui"

Source Files

Dependencies

@glinui/ui

Generated API Snapshot

Beta

Auto-extracted from TypeScript source in packages/ui/src/components/table.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.

Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata

Primary Props Type

TableProps

TableCellProps

PropTypeRequiredDefaultDescription
align"left" | "center" | "right"No"left"-
stickybooleanNofalse-
truncatebooleanNofalse-

TableHeadProps

PropTypeRequiredDefaultDescription
align"left" | "center" | "right"No"left"-
stickybooleanNofalse-

TableProps

PropTypeRequiredDefaultDescription
containerClassNamestringNo--
gridbooleanNofalse-
interactivebooleanNotrue-
layout"auto" | "fixed"No"auto"-
noWrapbooleanNofalse-
rowDividersbooleanNotrue-
size"sm" | "md" | "lg"No--
stickyFirstColumnbooleanNofalse-
stickyHeaderbooleanNofalse-
stripedbooleanNofalse-
variantSurfaceVariant | "liquid" | "matte" | "lift" | "default" | "raised" | "frosted"No-Visual variant. Omit for the ambient design style (glinr: lift wrapper with a raised header strip; plain: shadcn table). Vocabulary: glinr, solid, plain, soft, outline, ghost, gradient, glass. liquid, matte and the legacy `lift` alias stay supported.
wideboolean | stringNofalseForce a minimum table width so the wrapper scrolls horizontally on narrow screens.

TableRowProps

PropTypeRequiredDefaultDescription
toneTableRowToneNo"default"-

YesNoProps

PropTypeRequiredDefaultDescription
noLabelstringNo"No"Screen reader text for the no state.
valuebooleanYes-True renders a check, false renders a minus.
yesLabelstringNo"Yes"Screen reader text for the yes state.