Installation
Install @makeplane/propel and wire up its styles.
Install
pnpm add @makeplane/propel
Peer dependencies
pnpm add react react-dom tailwindcss
Import styles
@makeplane/propel ships a Tailwind v4 source file, not pre-built CSS — import it from your own
Tailwind entry so its tokens and utilities compile alongside your app’s:
@import "tailwindcss";
@import "@makeplane/propel/styles";
Set a theme
Propel’s color tokens are scoped to a data-theme attribute — set one on <html> or the app
root, or every semantic color resolves to nothing. Valid values are light, dark,
light-contrast, and dark-contrast:
<html data-theme="light"></html>
Propel ships no theme-switching JavaScript; toggling is your app’s concern — swap the attribute and every token follows.
Load the fonts
The tokens name Inter Variable (headings and body) and IBM Plex Mono (code) as their first choices but don’t bundle the files. Self-host them with Fontsource — or skip this and the stacks fall back to the system fonts:
pnpm add @fontsource-variable/inter @fontsource/ibm-plex-mono
@import "@fontsource-variable/inter";
@import "@fontsource/ibm-plex-mono/400.css";
@import "@fontsource/ibm-plex-mono/500.css";
Import components
There’s no root barrel — each component is imported from its own subpath, so you only pull in (and tree-shake to) what you use:
import { Button } from "@makeplane/propel/components/button";
Assets
Propel is otherwise asset-free — every component is markup, tokens, and CSS. The one exception is
LogoSpinner, whose animated Plane mark is a designed GIF (one per
theme) with a PNG still of the fully drawn mark beside it for reduced motion. It statically imports
those files, so it needs a bundler that turns an asset import into a URL — Vite, webpack 5+,
Parcel, or Rollup with an asset plugin. Every other component works without that support.
If you render on the server (SSR, or a prerendered SPA shell), also stop your bundler from
externalizing propel, or the asset import reaches Node — which cannot load a .gif — and the
render fails:
// vite.config.ts
export default defineConfig({
ssr: { noExternal: ["@makeplane/propel"] },
});
The GIFs and stills are also exported raw
(@makeplane/propel/components/logo-spinner/logo-spinner-light.gif,
…/logo-spinner-light-still.png), so an app’s own pre-hydration splash CSS can point at the same
artwork instead of keeping a copy.