opsinjs

Handbook

The mechanics layer is how you change things. It is kept deliberately separate from what a token means and from the generated list of every one.

60 shipped

The short version

Three pillars document the same system from three angles, and knowing which one you are in saves most of the time people lose looking things up:

Foundations = what a token means. Handbook and Theming = how you change it. Reference = the generated list of every one.

That sentence is printed at the top of all three sections and it is enforced: assert-ia fails the build when a Handbook page starts explaining meaning, or a Foundations page starts explaining overrides.

This is the middle layer Base UI deliberately leaves out. Base UI gives you unstyled primitives and a state-attribute contract, then stops. Stopping there is correct, because it is a primitive library. What it does not tell you is where the className goes, which attribute your transition should key off, where the client boundary falls in an App Router application, or what to assert in a test. Those questions have real answers, they are the same answers for everyone, and they belong somewhere.

How it works

The Handbook is organised by the moment you have the question.

Working with components. You have a component on screen and you want it to look or behave differently. Styling is the entry point and names the four hooks; Data attributes is the shared state vocabulary you style against; Composition and render covers merging opsinjs parts into your own elements; Forms is the wiring; Motion in practice is writing transitions that respect the reduced-motion contract; Icons is the icon slot.

Environment is the application around the component. Dark mode, Server and client components, Internationalisation and TypeScript.

Correctness and cost. Keeping it right as it grows. Naming conventions, Error codes, Performance and bundle size, Testing, and Tooling. Tooling covers the lint rules that enforce the invariants that documentation alone cannot.

Moving in and contributing. Migrating from shadcn/ui and Contributing.

How a Handbook page says what is real

A Handbook page carries no status; only a component page does. What it carries instead is a <NotBuiltYet> marker, and the marker is the thing to read. These are real now: the dark-mode strategy, the naming conventions and the contributing process all apply to this repository as it stands, and those pages carry no marker.

A page that does carry one is describing a mechanism nobody has checked against the sixty components now built. Code existing is not the same as the convention holding, and the marker tracks the second. Those pages are specifications you may review and argue with; they are not yet instructions you can follow.

Do this

Read Styling first if you are new. It is short, and it fixes the mental model that everything else assumes: four override hooks, in a fixed order of preference, and a rule about which one to reach for.

When you have a question that starts "how do I make it…", you are in the Handbook. When it starts "why is it…", you are in Foundations. When it starts "what is the exact list of…", you are in Reference.

Not this

Do not treat the Handbook as an API reference. The generated lists live in Reference and are produced from source by pnpm run generate. Those lists are every token, every data attribute, every CSS variable, every keyboard shortcut and every exported type. A Handbook page that starts enumerating is drifting, and any number typed into one by hand is wrong the moment the generator next runs.

Do not look for design rationale here either. Why the status axis has four levels is Health; why the material ladder has six rungs is Foundations → Materials.

Gotchas

  • CSS import order in globals.css is load-bearing and silent when wrong. The Tailwind v4 layer order, the fumadocs preset and the dark variant declaration interact, and a wrong order produces a site that mostly works. See Tailwind v4.
  • className on a compound component reaches the part you named, not the whole. The most common styling surprise; Styling explains the resolution order.
  • The client boundary is not where people expect. Importing one interactive component into a server component can pull a provider with it. See Server and client components.
  • Nothing here is generated except the counts. If a Handbook page shows you a table of token names, it is a Handbook page doing Reference's job. Report it.
  • Foundations says what each token means, and the reasoning behind the scales.
  • Theming and tokens is the other half of "how you change it": themes, presets, and adding your own tokens.
  • Reference has the generated lists, committed and searchable.
  • Contributing shows how to change opsinjs itself rather than your use of it.

On this page