Guide
Getting started
Open Props UI is a CSS UI library exploring how next-gen HTML & CSS features can change the way we create components. Designed to be used by professional teams as well as tinkering hobbyists.
Open Props UI is just CSS. You can copy any component CSS straight from the docs — no install required. The rest of this page is for when you want the full setup.
Install manually
The most flexible way to use OPUI. Download these files from the packages/opui/ folder on GitHub and drop them into your project for full control.
├─ opui └─ core ├─ normalize.css ├─ palette.css └─ utils.css └─ css ├─ components.css └─ theme.css └─ open-props.cssCombine them in your main stylesheet:
@layer openprops, theme, normalize, components.root, components.extended, utils;
@import "./open-props.css";@import "./core/palette.css";@import "./css/theme.css";@import "./core/normalize.css";@import "./css/components.css";@import "./core/utils.css";The import paths above assume the folder layout shown in the tree — adjust them if you place the files elsewhere.
theme.css generator
There's a visual editor for editing theme.css - try it out!
Theming
Once installed, here's how the theming system fits together: a single palette source feeds intent tokens, which components read from. The focus ring, control sizes, and shadows are separate scales you can tune independently.
Palette source
The 16-step --color-N ramp is generated from a single OKLCH input:
--palette-source. Setting it on :where(html) (or any
ancestor) regenerates the entire palette in place.
:where(html) { --palette-source: oklch(0.58 0.18 264); --palette-hue-rotate-by: 0;}- Must be
oklch(). Hex,rgb(), and named colors won't work — the relative-color math reads the source'scandhchannels directly. - Hue and chroma propagate; lightness is not used. The ramp keeps its own L curve, so the literal source color won't necessarily appear at any step.
-
--palette-hue-rotate-byis a separate knob for per-step warm/cool drift, in degrees.
To re-source the palette in a sub-tree (e.g. for status colors), override
--palette-source on a scoped selector:
:where(.ui-warning) { --palette-source: oklch(0.58 0.21 var(--hue-orange));}Motion
Use the --motion variable to turn motion on or off. The default value
is 1.
Adjust the motion speed using util classes on the html element, or
scope changes locally to an individual component instance.
Accessibility
By default, if a user has prefers-reduced-motion: reduce enabled
--motion variable automatically shifts to 0,
completely disabling transitions.
Global Classes
Adding these utility classes to the html element will override the
OS preference.
-
.ui-motion-off: sets--motion: 0(disables motion globally). -
.ui-motion-on: sets--motion: 1(enables default motion). -
.ui-motion-debug: sets--motion: 10(slows down transitions 10x to test and debug choreography).
<html lang="en" class="ui-motion-debug">Local Overrides
Components use a local --_motion variable that allows you to disable
motion for each component individually if you want.
<button class="ui-button" style="--_motion: 0"> Instant interaction</button>Install via NPM
Install the package and open-props — the source CSS imports below
resolve Open Props from your node_modules.
pnpm add opui-css open-props -Snpm install opui-css open-props -SUsage
Either import everything:
@import "opui-css/css/imports.css";Or pick and choose the parts you want to include:
@import "opui-css/open-props.css";@import "opui-css/core/palette.css";@import "opui-css/css/theme.css";@import "opui-css/core/normalize.css";@import "opui-css/css/components.css";@import "opui-css/core/utils.css";Install via CDN
For the quickest way to get started, you can include the styles via CDN.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/opui-css/dist/opui.css" />