Getting started
The four levels
CSS classes, utilities, copy-in source or npm. Same tokens, so they mix.
| Level | Feels like | Good for |
|---|---|---|
| Semantic classes | daisyUI | Any framework, plain HTML, emails, server templates |
| Utilities | Tailwind | One-off layouts and full control over markup |
| Copy-in | shadcn/ui | Owning and editing the source, while still getting updates |
| Installed | HeroUI / NextUI | Getting going fast with variant props and no source to maintain |
1. Semantic classes#
Pure CSS from @junco/tailwind. No JavaScript, works anywhere. Good for buttons, inputs, badges, cards, checkboxes and switches. Things that need behavior, like dialogs and menus, aren't offered here.
<button class="btn btn-primary">Save</button>
<span class="badge badge-success badge-dot">Paid</span>
<input type="checkbox" role="switch" class="switch" />2. Utilities#
Every token is a Tailwind utility: bg-surface, text-muted-foreground, rounded-card, shadow-float, duration-fast, ease-enter, animate-rise. Durations scale with the motion switch automatically.
<div className="rounded-card border border-border bg-card p-5">
<h2 className="text-sm font-medium">Usage</h2>
<p className="text-sm text-muted-foreground">You've used 80% of your plan.</p>
</div>3. Copy-in components#
Copy the source into your repo and change whatever you like. Unlike plain copy and paste, Junco remembers where each file came from, so junco diff shows upstream changes and junco update merges them, keeping your edits.
npx @junco/cli add select
# or with the shadcn CLI
npx shadcn add https://junco.madebytobi.com/r/select.json4. Installed components#
Install the package and import. Variants are props (variant, size, color) and states read like English (isLoading, isInvalid, isRequired). Every component takes className, and multi-part ones take classNames to style each slot.
import { Button, Field, Input } from "junco";
<Field label="Email" error={errors.email}>
<Input type="email" />
</Field>
<Button isLoading={saving}>Save</Button>Mixing levels#
Because everything reads the same CSS variables, a semantic .btn in a server-rendered email preview, an installed Button in your app and a copied-in, customized Dialog all change together when you change --primary.