Installation
Bst-Table is a headless engine (@bloomskill/table-engine) plus a style skin. You install
the engine, one skin, and that skin's peer libraries — then import the engine stylesheet. This page
has the exact packages and imports for each skin and framework, and a troubleshooting section for
the mistakes that bite first.
Supported React versions
Both the engine and the skins declare a peer dependency of react / react-dom >=18, so
Bst-Table runs on React 18 and React 19. There is no React 17 build.
Material UI skin
Install the engine, the MUI skin, and MUI + Emotion (the skin's peers):
npm install @bloomskill/table-mui @bloomskill/table-engine \
@mui/material @mui/icons-material @emotion/react @emotion/styled \
react react-dom
Peer versions the MUI skin expects: @mui/material >=6, @mui/icons-material >=6,
@emotion/react >=11, @emotion/styled >=11.
Import the engine stylesheet (always required) and render the skin:
import { BstTableMui } from '@bloomskill/table-mui'
import type { BstTableColumn } from '@bloomskill/table-engine'
import '@bloomskill/table-engine/styles.css'
type Person = { id: string; name: string; role: string }
const columns: BstTableColumn<Person>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'role', accessorKey: 'role', header: 'Role' },
]
export default function People({ rows }: { rows: Person[] }) {
return <BstTableMui data={rows} columns={columns} getRowId={(r) => r.id} />
}
shadcn / Radix skin
The shadcn skin ships a self-contained zinc palette (no Tailwind build required) and uses Radix for its menus:
npm install @bloomskill/table-shadcn @bloomskill/table-engine \
@radix-ui/react-dropdown-menu react react-dom
Peer version: @radix-ui/react-dropdown-menu >=2. Icon packs
(lucide-react, @tabler/icons-react, @phosphor-icons/react, …) are optional — the skin ships
built-in SVGs and only pulls a pack in if you opt into one of the @bloomskill/table-shadcn/icons/*
presets.
The shadcn skin needs two stylesheets — the engine's, then its own:
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' // shadcn skin needs both
type Person = { id: string; name: string; role: string }
const columns: BstTableColumn<Person>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'role', accessorKey: 'role', header: 'Role' },
]
export default function People({ rows }: { rows: Person[] }) {
return <BstTableShadcn data={rows} columns={columns} getRowId={(r) => r.id} dark />
}
Next.js (App Router)
The grid is an interactive client component — it uses React state, effects and browser APIs — so
the file that renders it must carry the 'use client' directive at the very top. Import the
stylesheet(s) from that same client module (or your root layout):
'use client'
import { BstTableMui } from '@bloomskill/table-mui'
import type { BstTableColumn } from '@bloomskill/table-engine'
import '@bloomskill/table-engine/styles.css'
type Row = { id: string; name: string }
const columns: BstTableColumn<Row>[] = [{ id: 'name', accessorKey: 'name', header: 'Name' }]
export function DataGrid({ rows }: { rows: Row[] }) {
return <BstTableMui data={rows} columns={columns} getRowId={(r) => r.id} />
}
You can still fetch on the server: keep your page.tsx a Server Component that loads the data,
then pass it as props into this client DataGrid. Only the grid itself needs 'use client'.
Vite / Create React App / plain React
No framework-specific setup — install the packages above, import the engine stylesheet once (in your entry file or the component), and render the skin. The CSS is plain (no Tailwind/PostCSS step needed for either skin's default palette).
Troubleshooting
The grid renders unstyled (no borders, no spacing)
You didn't import the engine stylesheet. import '@bloomskill/table-engine/styles.css' is
required for both skins; the shadcn skin additionally needs
import '@bloomskill/table-shadcn/styles.css'. Import them once, anywhere in your bundle.
Edits (or selection) land on the wrong row after sorting/filtering
You didn't pass getRowId. Editing, selection and clipboard target rows by id; without
getRowId the grid falls back to the row's position, so once the user sorts or filters, a change
meant for one row lands on whichever row now sits at that index. Always pass a stable id:
<BstTableMui data={rows} columns={columns} getRowId={(r) => r.id} />
The MUI skin ignores my theme (colors / dark mode)
@bloomskill/table-mui reads your MUI theme through ThemeProvider. If the grid isn't rendered
inside a ThemeProvider (or it sits above it in the tree), the grid falls back to MUI's default
theme. Wrap the grid — or your app — in the provider. See Styling & Theming.
useState/useEffect… only works in Client Components (Next.js / RSC)
The grid is a Client Component but it's being rendered from a Server Component without the directive.
Add 'use client' to the top of the file that renders <BstTableMui> / <BstTableShadcn> (see
Next.js above). Server Components can fetch the data and pass it in as props,
but the grid element itself must live in a client module.
Type error: Cannot find module '@bloomskill/table-engine/styles.css'
That import is a CSS side effect, not a type. Your bundler handles it at build time; if your
TypeScript setup type-checks CSS imports, add a declare module '*.css' ambient declaration (most
Next.js / Vite / CRA setups already ship one).
Next steps
- Recipes — complete, copy-pasteable apps: server data, save-to-API, custom cells.
- Getting Started — the five-minute tour and skin comparison.
- Feature Guides — every
enable*/show*flag.