Styling & Theming
Bst-Table renders its body from CSS variables (--bst-table-*), so each skin can map your app's
theme onto the grid — and you can override any part with plain CSS.
Material UI skin
@bloomskill/table-mui reads your MUI theme automatically. Wrap the grid in a ThemeProvider and
the toolbar, controls and grid body follow it — dark mode included.
import { ThemeProvider, createTheme } from '@mui/material/styles'
<ThemeProvider theme={createTheme({ palette: { mode: 'dark' } })}>
<BstTableMui data={rows} columns={columns} getRowId={(r) => r.id} />
</ThemeProvider>
With no ThemeProvider, MUI's default theme is used.

Example source
import React from 'react'
import { BstTableMui } from '@bloomskill/table-mui'
import type { BstTableColumn } from '@bloomskill/table-engine'
import '@bloomskill/table-engine/styles.css'
import { ThemeProvider, createTheme } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
type Row = { id: string; name: string; team: string; role: string; score: number }
const seed: Row[] = [
{ id: '1', name: 'Ada Lovelace', team: 'Platform', role: 'Engineer', score: 92 },
{ id: '2', name: 'Alan Turing', team: 'Research', role: 'Scientist', score: 88 },
{ id: '3', name: 'Grace Hopper', team: 'Platform', role: 'Engineer', score: 95 },
{ id: '4', name: 'Katherine J.', team: 'Research', role: 'Analyst', score: 90 },
]
const columns: BstTableColumn<Row>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'team', accessorKey: 'team', header: 'Team' },
{ id: 'role', accessorKey: 'role', header: 'Role' },
{ id: 'score', accessorKey: 'score', header: 'Score', sortFn: 'basic' },
]
export default function App() {
return (
<ThemeProvider theme={createTheme({ palette: { mode: 'dark' } })}>
<CssBaseline />
<BstTableMui data={seed} columns={columns} getRowId={(r) => r.id} pagination={{ pageSize: 5 }} />
</ThemeProvider>
)
}
shadcn / Radix skin
@bloomskill/table-shadcn ships a self-contained zinc palette by default — no Tailwind build
required, just import the stylesheet. To adopt your app's design tokens instead, set
theme="inherit": the grid re-points every variable at your host shadcn tokens (--background,
--primary, --border, --ring, --radius, font).
// self-contained zinc palette (default)
<BstTableShadcn data={rows} columns={columns} getRowId={(r) => r.id} />
// adopt the host app's shadcn tokens + OKLCH colors
<BstTableShadcn
data={rows}
columns={columns}
getRowId={(r) => r.id}
theme="inherit"
tokenFormat="oklch" // 'hsl' (default) | 'oklch'
/>
The shadcn skin, live — its self-contained zinc palette in dark mode, and inline editing:
Example source
import React from 'react'
import { BstTableShadcn } from '@bloomskill/table-shadcn'
import type { BstTableColumn } from '@bloomskill/table-engine'
import '@bloomskill/table-engine/styles.css'
import '@bloomskill/table-shadcn/styles.css'
type Row = { id: string; name: string; team: string; role: string; score: number }
const seed: Row[] = [
{ id: '1', name: 'Ada Lovelace', team: 'Platform', role: 'Engineer', score: 92 },
{ id: '2', name: 'Alan Turing', team: 'Research', role: 'Scientist', score: 88 },
{ id: '3', name: 'Grace Hopper', team: 'Platform', role: 'Engineer', score: 95 },
{ id: '4', name: 'Katherine J.', team: 'Research', role: 'Analyst', score: 90 },
{ id: '5', name: 'Edsger Dijkstra',team: 'Platform', role: 'Architect',score: 84 },
]
const columns: BstTableColumn<Row>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'team', accessorKey: 'team', header: 'Team' },
{ id: 'role', accessorKey: 'role', header: 'Role' },
{ id: 'score', accessorKey: 'score', header: 'Score', sortFn: 'basic' },
]
export default function App() {
// The shadcn skin's self-contained zinc palette, forced into dark mode via `dark`.
return (
<BstTableShadcn data={seed} columns={columns} getRowId={(r) => r.id}
dark pagination={{ pageSize: 5 }} />
)
}
Example source
import React from 'react'
import { BstTableShadcn } from '@bloomskill/table-shadcn'
import type { BstTableColumn } from '@bloomskill/table-engine'
import '@bloomskill/table-engine/styles.css'
import '@bloomskill/table-shadcn/styles.css'
type Row = { id: string; name: string; team: string; role: string; score: number }
const seed: Row[] = [
{ id: '1', name: 'Ada Lovelace', team: 'Platform', role: 'Engineer', score: 92 },
{ id: '2', name: 'Alan Turing', team: 'Research', role: 'Scientist', score: 88 },
{ id: '3', name: 'Grace Hopper', team: 'Platform', role: 'Engineer', score: 95 },
{ id: '4', name: 'Katherine J.', team: 'Research', role: 'Analyst', score: 90 },
{ id: '5', name: 'Edsger Dijkstra',team: 'Platform', role: 'Architect',score: 84 },
]
const columns: BstTableColumn<Row>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'team', accessorKey: 'team', header: 'Team' },
{ id: 'role', accessorKey: 'role', header: 'Role' },
{ id: 'score', accessorKey: 'score', header: 'Score', sortFn: 'basic' },
]
const editable: BstTableColumn<Row>[] = columns.map((c) =>
c.id === 'name' || c.id === 'score'
? { ...c, meta: { type: c.id === 'score' ? 'number' : 'text', editable: true } }
: c,
)
export default function App() {
const [rows, setRows] = React.useState(seed)
return (
<BstTableShadcn data={rows} columns={editable} getRowId={(r) => r.id}
enableEditing={{ mode: 'cell' }} onDataChange={setRows} />
)
}
Dark mode follows your ambient .dark class automatically (next-themes / shadcn). Force it
with dark={true} or dark={false}.
Custom CSS (any skin)
The engine exposes styling slots that layer on top of the built-in bst-* classes — they
never replace them, so your CSS builds on the theme rather than forking the renderer.
<BstTableMui
data={rows}
columns={columns}
getRowId={(r) => r.id}
className="my-card" // outer card
classNames={{ row: 'my-row', cell: 'my-cell' }}
styles={{ headerCell: { fontWeight: 700 } }}
/>
| Where | Prop | Applies to |
|---|---|---|
| Outer card | className / style | the adapter's card wrapper |
| Grid parts | classNames / styles | root, table, header, headerRow, headerCell, filterRow, body, row, cell, empty |
| Per column | meta.cellClassName / meta.headerClassName | that column's cells / header |
headerCell, row and cell slots also accept a function for per-row / per-cell logic, and
per-column meta styles win over the global slot (more specific).
Conditional formatting
For data-driven styling (thresholds, status colors), use declarative rules instead of hand-written
CSS — see enableConditionalFormatting and the runtime
Formats builder (showFormatBuilder). Rules compose with the CSS slots above.
Density & row height
showDensityToggle cycles compact / standard / comfortable row heights at runtime;
enableRowResize and enableAutoRowHeight (see Rows) let users or
content drive per-row height.