Theming Pick a theme
Pick a theme
Three themes ship with @pretable/ui — pretable, the house theme and the default, plus Excel and Material 3 as compatibility skins.
Three themes ship with @pretable/ui. One of them is the house theme and the default; the other two are compatibility skins, built to imitate a design language your application may already be speaking. All three declare the same 50 tokens, so switching between them is a one-line change to which file you import.
If you have no reason to choose otherwise, import pretable.css. The rest of this page is about what that choice is doing for you, and about the two cases where one of the skins is the better answer.
This page is itself styled with pretable.css — the grid below is not a screenshot, it is pretable.css rendering, on this page, right now:
A positions grid using all four presentation components together — PretableEntity for the symbol and name, PretableDelta for day P&L, PretableStatus for settlement, and PretableBadge for a risk or watch flag.
pretable — the house theme
@import "@pretable/ui/themes/pretable.css";
@import "@pretable/ui/grid.css";Why this one is the default
A component library never gets to paint the page it lands on. That sounds like a small constraint, and it is the one that decides how a data grid looks.
The reference designs everyone admires — the ones whose gridlines you have to look for before you see them — are cards sitting on a tinted page. The page supplies the contrast. The card can afford to be white and its rules can afford to be nearly invisible, because the boundary between the card and the world is already carried by the tone difference underneath it.
A grid dropped into someone else's application gets no such help. It may well land on pure white, and on pure white a faint hairline simply vanishes. The usual response is to darken the rules until they read against white — and that is exactly the move that makes most data grids look heavy. Every line has to work hard enough to be visible against the brightest possible ground, so the grid ends up drawn as a cage of borders rather than as a page of records.
pretable.css takes the other option: it paints its own canvas, inside the component. The header rail and the drag-to-group strip are tinted one small step off the data surface, and the whole thing is inset in a card that carries a hairline plus real elevation rather than a drawn frame. The tint is deliberately slight — a whisper off the white of the data, enough to register as a plane rather than as a fill. What it buys is that every rule drawn on that canvas now has something to read against, so the rules can stay true hairlines instead of being darkened into borders.
That is the whole argument for the default. It is the only one of the three themes that assumes nothing about the page underneath it.
What that looks like in practice
Look back at the grid above while you read these — every one of them is on the page, not just in the token table.
- Horizontal separation only.
--pretable-rule-verticalistransparent, so there is no column cage — nothing separates Position from Day P&L but whitespace. This matters more as rows get taller: in a wrapped 90px row, a vertical divider becomes a long empty channel running down through whitespace. - A quiet header. The header label is both smaller and greyer than the data it labels, because it is chrome rather than content — compare "Day P&L" in the header to the numbers underneath it.
- Color only where it carries meaning. Two meanings are admitted, and everything outside them is grey — that's why the grid above only has color in the delta arrows, the settlement status, and the flag badge. Interaction and selection is blue, at three values.
--pretable-accent(#3f5a7a) is the quiet one, desaturated and used only as chrome text and icons — an active filter funnel, the filter menu's Clear button, the calendar's month arrows on hover. A stronger system blue (#2554cf) carries what has to be unmissable:--pretable-focus-ring,--pretable-checkbox-checked-bg,--pretable-resize-handle-hover,--pretable-reorder-drop-indicator, and the same blue at 10% as the--pretable-selection-bgrange tint. And one pale blue paints a surface rather than ink:--pretable-bg-selected(#dfe6fb), with--pretable-text-selected(#131826) as the ink on it, behind a selected enum option or calendar day. That third value is opaque and a color of its own rather than a tint of either other blue, because it replaces the surface under text instead of compositing over it — which is also why--pretable-selection-bg, the one that does composite, is the translucent one. State is the four-value semantic ramp plus--pretable-text-error, and it's the ramp you're seeing in the P&L arrows and the settlement dot above. Nothing that is not carrying interaction, selection, or state gets a hue: every other surface, every rule, and all header and cell text is grey. And none of the blues is a brand color — they are system blues, so the grid reads as part of your application instead of competing with it. - No webfont. The sans and mono stacks resolve to whatever the platform already renders its UI in. A house theme that ships a font dependency cannot disappear into a host application, and it costs a network request before first paint.
- Light and dark.
:rootis light;[data-theme="dark"]restates every color token, and also flipscolor-schemeso form controls and scrollbars follow. See Light / dark switching for a live toggle. - Standard density by default — 48px rows under a 52px header, with compact and spacious tiers available at runtime.
Stay on pretable unless one of the two cases below describes your application.
This page can't put Excel and Material side by side with the demo above as three live grids. All three themes write their fifty tokens at a bare
:root— that's not a limitation of any one theme, it's what "one-line import, nothing else to configure" means for a consumer. On this page,:rootis shared by the whole site: the nav, the sidebar, and every other example on every other page all resolve--pretable-*from whatever last won:root. A second live theme here wouldn't sit beside the first — it would replace it, repainting the docs site around this one demo. The comparisons below are exact CSS and exact token values, not screenshots, but they're comparisons you run locally rather than ones this page can render live. See Token reference for every value side by side in a table.
Excel — the spreadsheet skin
@import "@pretable/ui/themes/excel.css";
@import "@pretable/ui/grid.css";Excel's job is to disappear into an application whose users already think in spreadsheets. It draws the full cage — vertical rules track the horizontal ones — and keeps every spreadsheet convention that goes with it: Aptos Narrow at 11pt (the modern Office default), an Excel-green (#107C41) active-cell border, no row hover at all, sharp 0-radius corners, and light gray #D4D4D4 gridlines. Its natural density is compact: 20px rows, 6px horizontal padding.
None of that is an accident of taste. A grid that reads as a spreadsheet is genuinely easier to trust when the surrounding product is a spreadsheet, and the density is the point rather than a compromise.
Reach for Excel when:
- Your application already looks Excel-adjacent — admin dashboards, log viewers, ticket queues, financial reports — and a grid with its own visual opinion would read as a foreign object.
- Information density matters more than whitespace, and your users would rather see forty rows than twenty.
- Your audience is technical and expects spreadsheet conventions: the cage, the tight rows, the green active cell.
Excel is light-only by design: there is no [data-theme="dark"] block in excel.css, so data-theme="dark" has nothing to match and the grid stays light. If you need dark mode, use pretable or Material, or override Excel's color tokens yourself inside your own [data-theme="dark"] block.
Material 3 — the Material skin
@import "@pretable/ui/themes/material.css";
@import "@pretable/ui/grid.css";Material 3's job is the same as Excel's, aimed at a different design system. It follows the M3 baseline scheme: neutral surface roles for chrome (N99 for cells, N96 one tonal step up for headers), the baseline blue (#0061a4) as primary, secondary-container for selection, an on-surface @ 8% state layer for hover, Roboto Flex for text, and the 12dp medium shape scale for corners. Its natural density is standard — 48px rows, 16px horizontal padding, sized for touch targets.
Reach for Material 3 when:
- Your product already uses Material elsewhere, and the grid should inherit that vocabulary rather than introduce a second one.
- You want the grid to sit as one component among many in a designed product, matching the surface roles and elevation language your other components already use.
- Your spacing and shape scales are Material's, and a grid on a different scale would visibly not line up.
Light lives at :root and dark at [data-theme="dark"]. Toggle the attribute on <html> to switch — see Light / dark switching for the wiring.
Material's dark mode needs nothing from you. It used to: its dark block left --pretable-checkbox-checked-fg at the light value #fff while --pretable-checkbox-checked-bg re-resolved to the dark primary, so a checked checkbox drew a white mark on light blue at 1.70:1. That was M3's roles showing through rather than a typo — the pair is primary / on-primary, and on-primary is genuinely a different color in each scheme, so no single literal serves both. The dark block now restates it at 7.73:1; Light / dark switching explains why the pattern is worth recognizing in a theme of your own.
Switching at build time
A theme is one import. To move off the default, swap the file:
- @import "@pretable/ui/themes/pretable.css";
+ @import "@pretable/ui/themes/material.css";Because all three define the same 50 tokens at :root, nothing else in your stylesheet has to change — anything you wrote against var(--pretable-*) keeps resolving.
You can also import more than one and pick between them with your own scoped CSS, but that is an advanced pattern and it ships bytes you are not using. For most applications, pick one theme at build time and override the individual tokens you need. See Override tokens for that pattern.
Where to go next
- Override tokens — change individual values within a theme.
- Light / dark switching — for
pretableand Material consumers. - Density switching — runtime compact / standard / spacious toggle.
- Custom themes — start from a shipped theme and author your own.