Theming Tailwind v4 + CSS-in-JS

Tailwind v4 + CSS-in-JS

@pretable/ui ships pure CSS, so it works in any styling toolchain.

@pretable/ui ships pure CSS, which means it works in any styling toolchain. Two specific integrations are documented below.

Token-aware toolbar

A plain CSS toolbar reads var(--pretable-*) tokens directly and repaints alongside the grid when dark mode toggles, proving the tokens resolve live for any styling approach, not just the shipped grid CSS.

.md

That toolbar strip isn't a Pretable component — it's a plain CSS class, in this demo's own stylesheet, reading var(--pretable-*). This is the mechanism both integrations below are built on.

This page can't run the Tailwind pt-* utility classes live: they only exist once @pretable/ui/tailwind.css is imported into your Tailwind build, and this docs site's own build doesn't import it (see apps/website/app/globals.css) — wiring it in is a site infrastructure change, out of scope for authoring an example. The utilities are exactly what's documented below; the mechanism proven above (var(--pretable-*) resolves live, for any CSS) is what makes them work, once the import is in place.

Tailwind v4

@pretable/ui includes an opt-in Tailwind v4 bridge. Importing tailwind.css registers --color-pt-* and --font-pt-* shortcuts in Tailwind's @theme namespace, giving you utility classes that resolve to the active Pretable tokens.

css
@import "tailwindcss";
@import "@pretable/ui/themes/pretable.css";
@import "@pretable/ui/grid.css";
@import "@pretable/ui/tailwind.css";

Now you can use Pretable's tokens in Tailwind utilities:

tsx
<aside className="bg-pt-bg-toolbar text-pt-text-dim p-4 border-b border-pt-rule">
  <p className="font-pt-mono text-pt-accent">Filter active</p>
</aside>

The pt- prefix avoids collisions with your own design tokens. Available utilities:

  • bg-pt-{token} — backgrounds (e.g., bg-pt-bg-grid, bg-pt-bg-header, bg-pt-bg-toolbar)
  • text-pt-{token} — text colors (e.g., text-pt-text-cell, text-pt-accent)
  • border-pt-{token} — border colors (e.g., border-pt-rule)
  • font-pt-{token} — font families (e.g., font-pt-mono, font-pt-sans)

The bridge covers 17 of the 50 tokens: five of the seven surfaces (bg-grid, bg-grid-alt, bg-header, bg-toolbar, bg-tooltip), the three text colors, rule and rule-strong, the four state colors, the accent, and the two font stacks. Those are the ones with a meaningful per-element analog — a color you might want to paint your own sidebar with, a font you might want to match.

The rest are deliberately absent. Density, radii, elevation, the semantic ramp, the icon size, the grid-control tokens, and the two grid-internal surfaces are consumed by grid.css against the grid's own markup, and a p-pt-cell-padding-x utility would suggest a relationship to your layout that does not exist. Reference any of them directly with var(--pretable-*) when you need one — the section on CSS-in-JS below is the same technique.

Cascade layer order

Tailwind v4 layers its Preflight reset in base. Declare the order once so the grid layer sits after the reset but before your utilities:

css
@layer theme, base, pretable, components, utilities;

This keeps Preflight from clobbering the grid while letting your utility classes win on individual cells. See Cascade & overrides.

Why the bridge is opt-in

You don't need the bridge to use @pretable/ui with Tailwind. The grid renders correctly with just a theme file and grid.css imported. The bridge is only useful if you want to style your own application's UI using Pretable's token palette — for example, building a sidebar that color-matches the embedded grid.

If you don't want the pt-* utilities, skip the tailwind.css import. The grid still works.

CSS-in-JS

CSS-in-JS libraries (styled-components, emotion, vanilla-extract, stitches, panda) all support runtime CSS custom properties. Reference Pretable's tokens directly via var(--pretable-*), the same reference the demo above's plain CSS class uses:

tsx
import styled from "styled-components";
 
const Toolbar = styled.div`
  background: var(--pretable-bg-toolbar);
  color: var(--pretable-text-dim);
  border-bottom: 1px solid var(--pretable-rule);
  font-family: var(--pretable-font-sans);
  padding: 12px 16px;
`;

Or with emotion's css prop:

tsx
import { css } from "@emotion/react";
 
<div
  css={css`
    background: var(--pretable-bg-grid);
    color: var(--pretable-text-cell);
  `}
/>;

CSS custom properties resolve at runtime, so they reflect whichever theme, density, and dark-mode variant is currently active. No build-time wiring needed, and unlike the Tailwind bridge this reaches all 50 tokens.

Composition with both

You can use the Tailwind bridge AND CSS-in-JS in the same app — they both resolve to the same --pretable-* source values. The bridge gives you ergonomic utility classes; CSS-in-JS gives you per-component scoped styles. Use whichever fits the surface you're building.

Where to go next

  • Override tokens — change Pretable's token values; both Tailwind utilities and CSS-in-JS automatically reflect the override.
  • Token reference — the full list of --pretable-* tokens you can reference in either approach.