Installation
Authenticate the registry once, add the packages, and load the stylesheets in order.
Authenticate the registry
The packages publish to a private GitHub Packages registry under the shuttering org. A consuming application authenticates the @shuttering scope in its .npmrc.
@shuttering:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}GITHUB_TOKEN is a personal access token (or a CI token) with the read:packages scope. Never commit the token — reference it from the environment as shown.
Export it locally, not only in CI
A fully-resolved lockfile is served from cache, so an unauthenticated shell installs fine and nothing looks wrong — until the first time you change a @shuttering version and pnpm needs a live fetch. It falls through to the public registry and reports @shuttering/error-pages is not in the npm registry, which reads as this package does not exist rather than you are not authenticated against the registry that has it.
Install
Add the packages an application needs.
pnpm add @shuttering/tokens @shuttering/ui @shuttering/motionLoad the stylesheets
Import the fonts and the token stylesheet at the application entry, in this order — the token stylesheet @imports Tailwind.
// application entry, in order:
import '@shuttering/tokens/fonts.css'
import '@shuttering/tokens/theme.css'Point Tailwind v4 at the installed component source so the utility classes used inside the components are generated:
/* your Tailwind v4 stylesheet */
@source '../node_modules/@shuttering/ui/dist';Using @shuttering/motion without the token stylesheets? Its effects (firePixelBurst, PixelGlimmer, firePixelRipple) self-inject the CSS they need, so they work with no extra import — or add @shuttering/motion/effects.css to ship it statically.
Prevent a theme flash
Inline the pre-paint theme script in the document <head>, before the stylesheet, so the first paint is already in the correct theme.
import { THEME_SCRIPT } from '@shuttering/utils'
// in your document <head>, before the stylesheet:
// <script dangerouslySetInnerHTML={{ __html: THEME_SCRIPT }} />The script reads the saved theme and palette from localStorage and applies them to <html> synchronously, before React mounts.
Requirements
- Node ≥ 24, pnpm 10
- React 19 and React DOM 19 (peer dependencies)
- Tailwind CSS v4 (CSS-first configuration; no config file)