Theming
Use built-in themes, switch at runtime, or compose your own theme from CSS tokens.
Wit Grid ships a shadcn-style, CSS-variable theming system: sixteen built-in themes, runtime switching with no
flash of the wrong theme, and full custom theme composition. All theme interaction goes through GridApi — the
same api you get from useGrid() or onGridReady. There's no separate theming object to construct.
Built-in themes
Each theme has its own palette and typeface.
| Theme | Look | Font |
|---|---|---|
dark (default) | Neutral graphite with an indigo accent | Inter |
light | Crisp white with a blue accent | Inter |
glass-dark | Frosted navy surfaces and a cool-blue accent | Inter |
glass-light | Bright frosted surfaces and a cobalt-blue accent | Inter |
ocean | Deep sea navy with a cyan glow | Plus Jakarta Sans |
fjord | Arctic slate with frost-blue accents (Nord) | IBM Plex Sans |
velvet | Midnight plum with a neon-pink accent | DM Sans |
ember | Warm charcoal lit with amber | Space Grotesk |
forest | Deep pine with emerald highlights | Source Sans 3 |
mono | A terminal: greys and a green cursor | JetBrains Mono |
paper | Cream paper, ink and terracotta | Source Serif 4 |
latte | Soft lavender-grey with a violet accent | Lexend |
blossom | Rosewater and raspberry | Nunito |
spreadsheet | Excel / Google Sheets: hairlines, a green cursor | Roboto |
dark-hc | Black, white and a bright blue focus | System |
light-hc | White, black and a deep blue focus | System |
The fonts come from Google Fonts; add BUILT_IN_THEME_FONTS_URL to your page to load them all, or load only the
ones you use. Without them each theme falls back to a system font stack.
import { BUILT_IN_THEME_FONTS_URL } from '@witbybit/wit-grid-react';
<link rel='stylesheet' href={BUILT_IN_THEME_FONTS_URL} />;Setting a theme
Set a built-in theme name declaratively via initialState. It's resolved once, atomically, before the grid's
first paint — no flash of the default theme.
<Grid initialState={{ themeName: 'light' }} />Switching themes at runtime
Get api from onGridReady (React) or the return value of createClientGrid / createInfiniteGrid /
createServerPageGrid (core), then call the theme methods directly on it:
api.setState({ themeName: 'dark' });
api.setState({ themeName: 'paper' });
const theme = api.getStatus().theme;
const unsubscribe = api.watch(
(grid) => grid.status.theme,
(theme) => {
console.log('Theme changed:', theme);
}
);Composing a custom theme
The quickest way is a palette: createTheme turns a dozen colours and a font into every token (selection,
popovers, group rows, skeletons, pinned-column shadows), and picks dark or light text for the accent so labels on
it stay readable.
import { createTheme } from '@witbybit/wit-grid-core';
export const acmeTheme = createTheme({
appearance: 'dark',
font: "'Inter', system-ui, sans-serif",
background: '#101418',
surface: '#0b0e11',
raised: '#171c22',
text: '#e8edf2',
muted: '#93a1b0',
border: '#1f2730',
borderStrong: '#2d3844',
accent: '#00d4ff',
hover: '#161c22',
error: '#ff6b6b',
radius: '10px',
});ThemeTokens is also a plain flat object — a themed variant of a built-in theme is just a spread, no helper function
required:
import { getBuiltInTheme, type ThemeTokens } from '@witbybit/wit-grid-core';
export const acmeTheme: ThemeTokens = {
...getBuiltInTheme('light'),
bgColor: '#1a1a2e',
textColor: '#eaeaea',
focusRing: '#00d4ff',
headerBg: '#0f0f1e',
headerText: '#b0b0b0',
};Frosted glass surfaces
Glass is an explicit theme opt-in. It gives floating menus, cell-editor popovers, tooltips, chart windows, sidebars, headers, and pinned rows a translucent tint and backdrop blur. It does not emulate refraction or distortion effects.
export const glassTheme = createTheme({
appearance: 'dark',
font: "'Inter', system-ui, sans-serif",
background: '#0b1020',
surface: '#111a30',
raised: '#17213a',
text: '#edf3ff',
muted: '#a9b8d3',
border: '#2a3855',
borderStrong: '#465b82',
accent: '#7c9cff',
hover: '#18233d',
error: '#fb7185',
glass: {
blur: '24px',
saturation: '160%',
// Optional per-surface tint overrides:
tint: 'rgba(23, 33, 58, 0.46)',
headerTint: 'rgba(17, 26, 48, 0.42)',
pinnedTint: 'rgba(17, 26, 48, 0.52)',
},
});Use glass: true for the same treatment with palette-derived defaults, or select the ready-made
glass-dark and glass-light themes. Users who request reduced transparency automatically receive solid
surfaces instead.
Performance
backdrop-filter is most expensive on persistent surfaces that repaint while content moves behind them. Glass is therefore off by default. Menus
and editors are low-cost; headers and pinned rows can add work during scroll. Measure scrolling on your largest supported grid and reduce blur
or disable glass if it affects your frame budget.
Apply it declaratively (atomic, no flicker) or imperatively:
<Grid theme={acmeTheme} />api.setOptions({ theme: acmeTheme });Incremental tweaks
The theme option holds tokens over the theme the person picked (the themeName state): pass only what you change,
api.setOptions({ theme: { focusRing: '#10b981' } }), and it stays over every theme they switch to.
System color scheme detection
systemColorScheme() reads the scheme the system prefers (light on a server): use it to pick the built-in theme
up front:
import { systemColorScheme } from '@witbybit/wit-grid-core';
<Grid initialState={{ themeName: systemColorScheme() }} />To keep the grid in sync as the OS preference changes live:
useEffect(() => {
const mql = window.matchMedia('(prefers-color-scheme: dark)');
const onChange = (e: MediaQueryListEvent) => api.setState({ themeName: e.matches ? 'dark' : 'light' });
mql.addEventListener('change', onChange);
return () => mql.removeEventListener('change', onChange);
}, [api]);Bridging into host CSS
Use themeToCSSVariables when you want to expose grid theme tokens as CSS custom properties on your own
stylesheet — useful for styling a toolbar or footer to match the active grid theme:
import { BUILT_IN_THEMES, getBuiltInTheme, themeToCSSVariables } from '@witbybit/wit-grid-react';
const styleVars = themeToCSSVariables(getBuiltInTheme('dark'));See the full theming guide in the repository
for the complete ThemeTokens token reference, merging semantics, and CSS variable customization.
Last updated on