Installation
Add a package, its peer dependencies, and its stylesheets.
Requirements
- React 19 and React DOM 19: peer dependencies of every package.
- A bundler that imports CSS from packages: Vite, Next.js, Rsbuild, webpack with a CSS loader. The packages are ESM only.
Install
Your app imports the token stylesheet (and, for Fumadocs, the stylesheet of @contour-ui/react)
directly, so list those packages as your own dependencies too: strict package managers such as
pnpm do not expose dependencies of dependencies to your code. Pick your package manager in any
block below: the others follow, and the site remembers it.
Essentials and Audio, the styled components:
npm install @contour-ui/react @contour-ui/tokenspnpm add @contour-ui/react @contour-ui/tokensyarn add @contour-ui/react @contour-ui/tokensbun add @contour-ui/react @contour-ui/tokensHeadless, no styles and no tokens:
npm install @contour-ui/headless-reactpnpm add @contour-ui/headless-reactyarn add @contour-ui/headless-reactbun add @contour-ui/headless-reactFumadocs, a docs site on fumadocs-core:
npm install @contour-ui/fumadocs @contour-ui/react @contour-ui/tokens fumadocs-core fumadocs-mdxpnpm add @contour-ui/fumadocs @contour-ui/react @contour-ui/tokens fumadocs-core fumadocs-mdxyarn add @contour-ui/fumadocs @contour-ui/react @contour-ui/tokens fumadocs-core fumadocs-mdxbun add @contour-ui/fumadocs @contour-ui/react @contour-ui/tokens fumadocs-core fumadocs-mdxA docs site on Fumadocs takes a few more steps: Setup wires it into React Router or Next.js.
Load the stylesheets
@contour-ui/react styles its components with plain CSS that reads token variables. Import the
stylesheets once, in your app entry, in this order:
import '@contour-ui/tokens/tokens.css'; // tokens: --ct-* custom properties for every theme
import '@contour-ui/tokens/fonts.css'; // IBM Plex Sans and JetBrains Mono
import '@contour-ui/react/styles.css';The stylesheets do not import each other, so your app decides what loads and when, and tokens load once.
fonts.css declares the font faces the type tokens refer to (SIL Open Font License). Skip it if
your app already provides these fonts; the token font stacks fall back to system fonts.
Headless needs no stylesheet. A docs site on Fumadocs loads @contour-ui/fumadocs/styles.css
after the tokens and before @contour-ui/react/styles.css, since its first rule sets the order of
the cascade layers (Fumadocs).
Cascade layers
Every rule of @contour-ui/react/styles.css sits in a
cascade layer: contour.components,
inside the contour layer. CSS outside any layer wins over layered CSS whatever its selectors, so
your own stylesheet overrides a component without heavier selectors or !important:
/* Wins over the button's own rule: same selector, but not in a layer. */
.contour-button {
border-radius: 0;
}- Tokens.
tokens.cssonly defines custom properties on:root, outside any layer, so the layers do not affect it.
Resets count as your CSS too: a reset loaded outside a layer overrides the components as well.
Give it a layer declared before contour:
@layer reset, contour;
@import './reset.css' layer(reset);With Tailwind CSS
Tailwind CSS v4 puts its CSS in four layers: theme, base (Preflight, its reset), components
and utilities. Layers rank in the order they are first declared, the last one strongest, so
declare the whole order once, at the top of the stylesheet that imports Tailwind:
@layer theme, base, contour, components, utilities;
@import 'tailwindcss';contour comes after base, so Preflight does not strip the components' padding, borders and
backgrounds, and before utilities, so a utility class overrides a component, as in
<Button className="rounded-none">. Without this line the order follows whichever stylesheet
loads first: if @contour-ui/react/styles.css comes first, Preflight resets the components; if
Tailwind's does, utilities cannot override them.
Page background
Tokens do not style the page itself. Give the document the canvas colors so the space around components follows the theme:
body {
margin: 0;
background: var(--ct-color-bg-canvas);
color: var(--ct-color-fg-default);
font: var(--ct-text-body);
letter-spacing: var(--ct-text-body-letter-spacing);
}A minimal app
import { Button } from '@contour-ui/react';
import { createRoot } from 'react-dom/client';
import '@contour-ui/tokens/tokens.css';
import '@contour-ui/tokens/fonts.css';
import '@contour-ui/react/styles.css';
import './app.css';
const root = document.querySelector('#root');
if (root !== null) {
createRoot(root).render(<Button>Hello, contour-ui</Button>);
}