Static Table
A plain, server-renderable table with Table's styling and no client JavaScript, for listings that don't need sorting, selection, or grid navigation.
Overview
StaticTable renders a <table> with the same styling props as Table and none of its behavior. You write the rows as ordinary <thead>/<tbody>/<tfoot>/<tr>/<th>/<td> markup and it renders them as-is. It has no hooks and no state, so it ships no JavaScript to the browser.
Reach for it when a page only needs consistent table styling around server-rendered rows: a listing of links, a history log, a table with server-action forms in its cells. Reach for Table instead when you need sorting, row selection, or arrow-key grid navigation.
import { StaticTable } from '@chassis-ui/react/static-table'
const users = [
{ id: 1, name: 'Mark Otto', username: 'mdo', topics: 42 },
{ id: 2, name: 'Jacob Thornton', username: 'fat', topics: 17 },
{ id: 3, name: 'Larry Bird', username: 'twitter', topics: 8 }
]
export const Example = () => (
<StaticTable caption="Most active members">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Profile</th>
<th scope="col">Topics</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id} id={user.username}>
<td>{user.name}</td>
<td>
<a href={`#${user.username}`}>@{user.username}</a>
</td>
<td>{user.topics}</td>
</tr>
))}
</tbody>
</StaticTable>
)In Server Components
Import it from its own entry point, @chassis-ui/react/static-table. That's the one entry point in the package without a 'use client' directive, so it renders as a genuine Server Component: no client boundary, no hydration, and no JavaScript for it in the page's bundle.
// app/members/page.tsx — a Server Component
import Link from 'next/link'
import { StaticTable } from '@chassis-ui/react/static-table'
export default async function Members() {
const members = await getMembers()
return (
<StaticTable hover striped>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Topics</th>
</tr>
</thead>
<tbody>
{members.map((member) => (
<tr key={member.id}>
<td>
<Link href={`/u/${member.username}`}>{member.name}</Link>
</td>
<td>{member.topics}</td>
</tr>
))}
</tbody>
</StaticTable>
)
}StaticTable is exported from the root @chassis-ui/react entry too, for use inside Client Components. Imported from there into a Server Component, it still works, but it becomes a client component, because the root entry is a client boundary.
Variants
bordered, borderless, hover, sm, striped, color, and align apply the same classes they do on Table.
| Name | Role |
|---|---|
| Mark Otto | Engineer |
| Jacob Thornton | Designer |
| Larry Bird | Engineer |
| 3 members | |
import { StaticTable } from '@chassis-ui/react/static-table'
const rows = [
{ id: 1, name: 'Mark Otto', role: 'Engineer' },
{ id: 2, name: 'Jacob Thornton', role: 'Designer' },
{ id: 3, name: 'Larry Bird', role: 'Engineer' }
]
export const Example = () => (
<StaticTable aria-label="Team" bordered hover sm striped>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Role</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.id}>
<td>{row.name}</td>
<td>{row.role}</td>
</tr>
))}
</tbody>
<tfoot>
<tr>
<td colSpan={2}>3 members</td>
</tr>
</tfoot>
</StaticTable>
)Responsive and stacked tables
responsive wraps the table in a horizontally scrolling container: true for all viewports, or a breakpoint name to scroll only below it. stacked converts rows into label/value blocks below a container width.
Table derives each stacked label from its column header. A static table has no column data to read, so give each <td> a data-cell attribute with the label to show. Resize the panel below to see it switch.
| Name | Role | Status | |
|---|---|---|---|
| Alice Martin | Admin | alice@example.com | Active |
| Bob Chen | Editor | bob@example.com | Active |
| Carol White | Viewer | carol@example.com | Inactive |
import { StaticTable } from '@chassis-ui/react/static-table'
const rows = [
{ id: 1, name: 'Alice Martin', role: 'Admin', email: 'alice@example.com', status: 'Active' },
{ id: 2, name: 'Bob Chen', role: 'Editor', email: 'bob@example.com', status: 'Active' },
{ id: 3, name: 'Carol White', role: 'Viewer', email: 'carol@example.com', status: 'Inactive' }
]
export const Example = () => (
<StaticTable aria-label="Users" stacked="md">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Role</th>
<th scope="col">Email</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.id}>
<td data-cell="Name">{row.name}</td>
<td data-cell="Role">{row.role}</td>
<td data-cell="Email">{row.email}</td>
<td data-cell="Status">{row.status}</td>
</tr>
))}
</tbody>
</StaticTable>
)Accessibility
Since StaticTable renders your markup unchanged, table semantics are yours to write: add scope="col" (or scope="row") to header cells, and give the table an accessible name with caption, aria-label, or aria-labelledby.
API
StaticTable
| Prop | Type | Default |
|---|---|---|
align? | "bottom" | "middle" | "top" | — |
| Set the vertical alignment of cell content. | ||
bordered? | boolean | — |
| Add borders on all sides of the table and cells. | ||
borderless? | boolean | — |
| Remove borders on all sides of the table and cells. | ||
caption? | ReactNode | — |
| Content shown above the table, functioning as a heading for it. | ||
children? | ReactNode | — |
The table's own markup — plain <thead>/<tbody>/<tfoot>/<tr>/<th>/<td> elements,
rendered as-is. | ||
className? | string | — |
| A string of all className you want applied to the component. | ||
color? | ContextColor | — |
| Sets the color of the component. | ||
hover? | boolean | — |
| Enable a hover state on table rows. | ||
responsive? | boolean | Breakpoint | — |
| Make any table responsive across all viewports or pick a maximum breakpoint. | ||
sm? | boolean | — |
| Make table more compact by cutting all cell padding. | ||
stacked? | boolean | Breakpoint | — |
Convert rows into stacked label/value blocks below a container width, for tables with too
many columns to read comfortably even with horizontal scrolling. true always stacks; a
breakpoint name stacks only below it. Implies responsive when responsive isn't set
separately. Unlike Table, which derives each cell's label from its column header, a static
table has no collection to read labels from — give each <td> a data-cell attribute with
the label to show before its value. | ||
striped? | boolean | — |
| Add zebra-striping to table rows. | ||