Shared tokens, Tailwind preset, and React primitives for CourseLit, MediaLit, SendLit, and FrontLit.
The tokens + Tailwind preset are the product; the React components are reference/fallback (see step 5). Consuming apps typically use only the CSS and the preset and keep their own shadcn components.
Published to npm as a public package. The current release line is a prerelease
under the alpha dist-tag.
Warning
latest currently also points at 0.1.0-alpha.0. npm always sets
latest on a package's first-ever publish, regardless of --tag — this is
unavoidable until a real stable version is cut, at which point publishing it
moves latest forward automatically. Until then, always pin the exact
version — do not npm install @codelitdev/design-system bare, and do not
use a caret/tilde range (^0.1.0-alpha.0 would still resolve to a
prerelease, which is at least explicit — but a bare install with no version
silently means "whatever latest is," which right now is this alpha).
npm install @codelitdev/design-system@0.1.0-alpha.0Inside a workspace/monorepo you can still consume it as workspace:* when the
package is vendored locally.
- Import the token layer once, e.g. in
app/globals.css:
@import "@codelitdev/design-system/styles.css";This replaces the default shadcn :root/.dark block — variable names match, so existing shadcn components need no code changes.
- Extend your Tailwind config:
// tailwind.config.js
const codelitPreset = require("@codelitdev/design-system/tailwind-preset");
module.exports = {
presets: [codelitPreset],
content: [...],
};- Scope the product on the
<html>element (not<body>):
<html data-product="sendlit"> {/* courselit | medialit | sendlit | frontlit, omit for CodeLit amber */}Important
Put data-product on <html>, not <body>. The product scope only overrides
--primary/--ring; any token you alias at :root that references --primary
(e.g. shadcn's --sidebar-primary: var(--primary)) resolves that var() at the
declaring element. If the override sits on <body> (a child of :root), those
:root aliases freeze to the base amber and never pick up the product accent —
while direct bg-primary utilities still turn green, producing a confusing split.
-
Fonts: load Hanken Grotesk + Spline Sans Mono via
next/font/google(or your framework's font loader), mapped to--font-sans/--font-mono. -
Components — install from the shadcn registry (see Components below). These are real shadcn/Radix components styled to the design system, so your app's buttons/badges/cards are the DS's — no hand-porting. The plain-React
src/components/classes (components.css) remain as visual reference only. -
Logos:
@codelitdev/design-system/assets/logo-<product>.svg.
The design system ships its components as a shadcn registry so every product
installs the same styled components (buttons, badges, cards, …) via the shadcn
CLI — keeping all four apps on one component layer instead of each re-styling its
own. They're standard shadcn/Radix components; they pull their look from the DS
tokens, so make sure @codelitdev/design-system/styles.css is imported (above).
Add the registry namespace to your app's components.json:
Then install components like any other shadcn component:
npx shadcn@latest add @codelit/button @codelit/badge @codelit/cardOr install a single component directly by URL, no config:
npx shadcn@latest add https://raw.githubusercontent.com/codelitdev/design-system/main/public/r/button.json| Component | Notes |
|---|---|
button |
primary / secondary / outline / ghost / soft / destructive; sm md lg (30/36/42px) |
icon-button |
Square icon-only; ghost / outline; sm md |
badge |
default / neutral / success / warning / destructive / outline; dot prop |
card |
+ CardHeader CardTitle CardDescription CardContent CardFooter |
input |
Accent-wash focus ring; aria-invalid → destructive |
textarea |
Multiline form of input |
label |
13px semibold field label |
checkbox |
18px, 5px radius, accent fill when checked |
radio-group |
+ RadioGroupItem |
switch |
36×21 track, accent when on |
select |
Trigger matches input; token-styled popover |
tabs |
Segmented; active trigger lifts onto a card surface |
dialog |
Warm scrim, 16px radius; full Radix parts |
tooltip |
Dark chip; TooltipProvider included |
toast |
Presentational card (default/success/destructive) — drive with your own queue |
Install everything at once:
npx shadcn@latest add @codelit/button @codelit/icon-button @codelit/badge @codelit/card \
@codelit/input @codelit/textarea @codelit/label @codelit/checkbox @codelit/radio-group \
@codelit/switch @codelit/select @codelit/tabs @codelit/dialog @codelit/tooltip @codelit/toastMaintainers: component sources live in registry/codelit/ui/. After changing
one, rebuild the served JSON with pnpm registry:build (→ public/r/*.json) and
commit it — the raw-URL install serves those committed files.
Prereleases go under the alpha dist-tag so a plain npm install never grabs
one. Always publish with an explicit tag — publishConfig.tag is not
honored by npm 11.x, so a bare npm publish would land on latest:
npm run release:alpha # → npm publish --tag alpha
# add --otp=<code> if 2FA is enabledVerify: npm view @codelitdev/design-system dist-tags should show the
prerelease under alpha and leave latest untouched.
Apache-2.0 — see LICENSE.
{ "registries": { "@codelit": "https://raw.githubusercontent.com/codelitdev/design-system/main/public/r/{name}.json" } }