Get started
Install
Two ways in. A hosted stylesheet when you want tokens in the next minute, and a pinned package when you want a build that cannot change underneath you.
Hosted, for prototypes
One line. Fonts, tokens, three themes and the base rules.
@import url("https://flux.kaptio.com/tokens/v2/flux.css");Or from HTML, which avoids the request waterfall an @import creates:
<link rel="stylesheet" href="https://flux.kaptio.com/tokens/v2/flux.css" />The /v2/ in that path is deliberate. /tokens/flux.css without it is Flux 1.x, frozen, still imported at runtime by applications that cannot redeploy to follow a change. 2.0 is not a drop-in replacement for it — see Upgrading.
Package, for applications
Pinned, versioned, published to the Kaptio GitLab registry.
# .npmrc at the repo root. The registry is private, so every install authenticates.
@kaptio:registry=https://gitlab.com/api/v4/projects/80171946/packages/npm/
//gitlab.com/api/v4/projects/80171946/packages/npm/:_authToken=${CI_JOB_TOKEN}npm install @kaptio/flux-tokens@2.3.0A pipeline in another project can read the package with CI_JOB_TOKEN once that project is on the job token allowlist of kaptio1/kaptio-tooling/kaptio-flux. Ask a maintainer to add it. Locally, set CI_JOB_TOKEN to a personal access token with the read_api scope; npm fails on the unset variable otherwise.
/* In your root stylesheet, before anything of your own. */
@import "@kaptio/flux-tokens/flux.css";| Import | Gives you |
|---|---|
@kaptio/flux-tokens/flux.css | Fonts, all three tiers, base rules. The usual choice. |
@kaptio/flux-tokens/flux-tokens.css | Tokens only. Use when you self-host fonts. |
@kaptio/flux-tokens/flux.json | Every token as data, for tooling. |
@kaptio/flux-tokens/flux-tailwind.css | The Tailwind v4 preset. |
With Tailwind
The preset clears Tailwind's defaults rather than sitting beside them.
@import "tailwindcss";
@import "@kaptio/flux-tokens/flux.css";
@import "@kaptio/flux-tokens/flux-tailwind.css";Order matters. The preset resets Tailwind's colour, spacing, radius and font namespaces to empty and then repopulates them from Flux tokens. After it loads,bg-primary-400 is Kaptio Seagreen and bg-blue-500 does not exist.
That is deliberate. Leaving Tailwind's palette in place means every generated component is one autocomplete away from off-brand, and no amount of documentation closes that gap.
Every stock colour family resolves to the nearest Flux ramp step, and steps 700 and darker stay readable as text, at 4.5:1 or better on white. The weight utilities resolve to the loaded weights: font-medium is Lexend Light andfont-semibold Lexend Bold. Load flux-prototype.css before the preset and the same utilities follow the prototype weights instead.
bg-[#056F82], p-[14px],text-[15px]. It bypasses the token layer entirely, and it is invisible to every theme.The component layer
Optional. Working CSS for the 48 documented components, built from tier-3 tokens.
@import "@kaptio/flux-tokens/flux.css";
@import "@kaptio/flux-tokens/flux-components.css";<script src="https://flux.kaptio.com/tokens/v2/flux-components.js" defer></script>Import it and .flux-button, .flux-card and the rest work immediately, in all three themes. Or read it as the reference implementation and reproduce the same token bindings in React, Lightning Web Components or whatever the project uses — the bindings are the contract, not the class names.
Include flux-components.js on any page with an interactive component. It provides keyboard handling, visible-value updates and form values for Select, Date picker, Slider and Search; chart inspection and Heatmap navigation; the data table, Menu, Tooltip, App shell, Reorder and Editable cell; and opens Modal and Drawer from invoker commands in browsers that lack them. Markup added after the page loads is wired too; seeIn React and other frameworks. Each component’s API lists the attributes that require it. Static components such as Button, Card, Badge and a plain Table need no script.
In React and other frameworks
The script follows the document, so markup a framework mounts later works without wiring.
<!-- index.html. A bundler that inlines flux.css moves its font @import below
other rules, where browsers ignore it, so load the fonts here instead. -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lexend:wght@300;700&family=JetBrains+Mono:wght@400..700&display=swap" />
<!-- Prototypes only, beside flux-prototype.css. -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans+Flex:wght@400;500;700&family=Manrope:wght@400;500;600&display=swap" />// main.tsx, once, before the app renders.
import '@kaptio/flux-tokens/flux-components.js';flux-components.js enhances every component when it enters the document — on load, on a lazily loaded route, or when a framework mounts or re-renders it — and when the parts it needs arrive later, such as a Select’s options. It releases the listeners a component attaches to the page when the component leaves, and restores them if it is inserted again. Enhancing is idempotent, so React’s StrictMode double mount is safe. For an explicit lifecycle, such as a test that renders into a detached container, call Flux.enhance(root) andFlux.dispose(root).
Three components move or rewrite markup the framework owns. When the framework renders that state, cancel the component’s event with preventDefault() and render the change from event.detail:
| Event | On | When cancelled |
|---|---|---|
flux-sort | Data table | Rows and aria-sort are left to the framework. The sort is still announced. |
flux-select-change | Select | The value text, aria-selected and the hidden input are left to the framework. |
flux-reorder · flux-board-move | Reorder, Board | The item goes back where it started, and the framework renders the move. |
const ref = useRef(null);
useEffect(() => {
const table = ref.current;
const onSort = (event) => {
event.preventDefault();
setSort({ column: event.detail.column, direction: event.detail.direction });
};
table.addEventListener('flux-sort', onSort);
return () => table.removeEventListener('flux-sort', onSort);
}, []);
return <div data-flux-table ref={ref}>…</div>;What each artifact contains
| File | Size | Contents |
|---|---|---|
flux.css | 53.6 kB | Font imports, 818 tokens across three tiers and three themes, base rules. |
flux-tokens.css | 51.8 kB | The same tokens, without font imports or base rules. |
flux.json | 145.5 kB | Every token as structured data, grouped by tier and theme. |
flux-tailwind.css | 21.9 kB | Tailwind v4 theme block. Clears defaults, remaps names. |
flux-components.css | 157.2 kB | The 48 components, as framework-agnostic CSS. |
flux-components.js | 103.2 kB | Behaviour for the interactive components: keyboard handling, form values and invoker commands. |
Verify the install
Three checks that catch the usual failures.
- Body text should be Lexend Light, not the system sans. If it is not, the font request failed or a later stylesheet is overriding
font-family. - Tab to any link. The focus ring should be teal, 2px, offset. A blue ring means a reset is loading after Flux; a missing ring means something set
outline: none. - Set
data-flux-theme="dark"on<html>. If the page inverts cleanly, you are on the semantic tier. If parts stay light, those parts are referencing primitives or raw values.
<html lang="en" data-flux-theme="dark">