Skip to main content

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.

The MUI skin in dark mode, following a dark ThemeProvider palette

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>
)
}
Loading live example…

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 }} />
)
}
Loading live example…
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} />
)
}
Loading live example…

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 } }}
/>
WherePropApplies to
Outer cardclassName / stylethe adapter's card wrapper
Grid partsclassNames / stylesroot, table, header, headerRow, headerCell, filterRow, body, row, cell, empty
Per columnmeta.cellClassName / meta.headerClassNamethat 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.