Skip to content

Headless

Unstyled React components with the structure and behavior of contour-ui, for your own look.

Headless components render the DOM structure and behavior of interactive components, and nothing else: no CSS, no tokens, no themes. The styled components of @contour-ui/react are the same components with the look of contour-ui, so switching one between the two packages keeps its parts and props. Components without behavior, such as buttons and cards, exist only in the styled package.

Setup

pnpm add @contour-ui/headless-react

There is no stylesheet to load. React 19 and React DOM 19 are peer dependencies.

Usage

import { Placeholder } from '@contour-ui/headless-react';

export function Note() {
  return <Placeholder.Root className="note">Unstyled</Placeholder.Root>;
}

Styling

Style parts with your own classes, or target them by their data attributes. Every part carries data-scope (the component) and data-part (the part):

[data-scope='placeholder'][data-part='root'] {
  padding: 8px 12px;
  border: 1px solid currentColor;
  border-radius: 4px;
}

Want the contour-ui look for some of your own pieces? The token variables work with Headless too: load @contour-ui/tokens/tokens.css and see Styling with tokens.

Build your own parts

Every part renders through Primitive: Primitive.div, Primitive.button, Primitive.a and the other elements parts are made of. A primitive takes its element's props and ref, plus asChild, which renders the only child instead and merges the props into it:

import { Primitive } from '@contour-ui/headless-react';
import { Link } from 'react-router';

<Primitive.a asChild className="nav-link">
  <Link to="/docs">Docs</Link>
</Primitive.a>;

When a part combines its own props with the ones it receives, use the same helpers:

  • mergeProps(...sources) runs every event handler (the last source's first), joins class names, merges styles, and lets the last value win for anything else.
  • composeRefs(...refs) feeds one element to several refs; inside a component, useComposedRefs(first, second) keeps the combined ref stable between renders.

Components

Utilities

Building blocks of the overlays, for parts of your own too.