Theme
On this page (7)

§Quick start

All files are served via jsDelivr CDN directly from the GitHub repo. No download or install required - just reference the URLs in your HTML.

1

Add the base: tokens + utilities

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/core.css">
<!-- optional: a theme preset AFTER core overrides the default tokens -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/theme/bubblegum.css">

core.css defines every token for the default light and dark theme plus the sizing, layout and accessibility utilities the examples use (flex, gap-4, stack, sr-only …). To switch themes, load one preset from dist/theme/ after it - that's all the theme selector in this documentation site is doing. Compatible with tweakcn.com theme exports.

2

Add the icons

<script src="https://unpkg.com/lucide@1.8.0"></script>
<script>lucide.createIcons();</script>

Lucide provides ~1,500 icons via CDN. Use <i data-lucide="name"></i> anywhere in your HTML. The script replaces each element with an inline SVG on page load. See the Icon page for details.

3

Add the components

<!-- Everything at once: every component's CSS + the bundle (embeds the core runtime) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/all.css">
<script type="module" src="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/all.js"></script>
<!-- …or only what you need: per-component CSS, then core.js + per-component JS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/button/button.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/dialog/dialog.css">
<script type="module" src="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/core.js"></script>
<!-- JS - after core, when the component needs it -->
<script type="module" src="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/dialog/dialog.js"></script>

Two delivery modes, one implementation: load core plus the components you use, or load all alone - both include the df$ runtime (defuss-query + defuss-morph) through core; documentation code is separate, and there is no framework or jQuery dependency. all.css / all.js bundle the core runtime plus every component (this documentation site loads exactly these two files). Prefer a smaller payload? Load core.js once, then pick per-component .css + .js files from components/{name}/ - a component script without core fails fast with one actionable load-order error.

4

Read the component skill, write the HTML

<button class="btn" data-variant="default"
        data-dialog-trigger="confirm"
        aria-haspopup="dialog">
  Open Dialog
</button>
<dialog id="confirm" class="dialog"
        role="dialog" aria-modal="true"
        aria-labelledby="confirm-title">
  <div class="dialog-content">
    <div class="dialog-header">
      <h2 class="dialog-title" id="confirm-title">Are you sure?</h2>
      <p class="dialog-description">This action cannot be undone.</p>
    </div>
    <div class="dialog-footer">
      <button class="btn" data-variant="outline" data-dialog-close>Cancel</button>
      <button class="btn" data-variant="default">Confirm</button>
    </div>
  </div>
</dialog>

Each component folder has a component-skill.md that documents the exact HTML structure, attributes, variants, and ARIA. Read it, copy the pattern, fill in your content. The CSS and JS handle the rest.

5

That's it

Serve your HTML via any local server (e.g. npx serve). ES modules require HTTP - they don't run from file://. Dark mode toggles automatically when you add class="dark" to <html>.

§With a package manager

In a project that already has a package manager and a bundler (Vite, webpack, Rollup, Parcel, esbuild, Bun), install the package and import the same files in the same order - side-effect imports, once, in the app entry. The package ships plain CSS and ES modules; the bundler only resolves the paths.

npm install defuss-shadcn   # or: bun add / pnpm add / yarn add defuss-shadcn
// everything: tokens + utilities → all component CSS → runtime + all behavior
import 'defuss-shadcn/dist/components/core.css';
import 'defuss-shadcn/dist/components/all.css';
import 'defuss-shadcn/dist/components/all.js';
// …or only what you need (core.js MUST precede every component .js)
import 'defuss-shadcn/dist/components/core.css';
import 'defuss-shadcn/dist/components/dialog/dialog.css';
import 'defuss-shadcn/dist/components/core.js';
import 'defuss-shadcn/dist/components/dialog/dialog.js';

Icons and charts stay separate packages: npm install lucide (then createIcons({ icons })) for <i data-lucide>, and npm install echarts assigned to globalThis.echarts before a chart mounts. For AI agents, the package's skills/defuss-shadcn/SKILL.md condenses both install paths, the rules, and an index of every component skill and documentation page - install it into your coding agent with one command (see Vibe Coding / Agentic Engineering).

§With an AI coding agent

Building with Claude Code, Codex, Cursor, Gemini CLI, Copilot or Windsurf? Install the defuss-shadcn Agent Skill and let the agent write the HTML - see Vibe Coding / Agentic Engineering for the one-command installs, updates and how to prompt it.

§Pinning a version

Replace @latest with a specific version tag to lock your project to a release:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@v0.1.1/dist/theme/utils/default-semantic-tokens.css">

This ensures your project won't break when new versions are published. Check the releases page for available versions.

§Self-hosting

Download the full system and drop it into any project. All the files are static - no build step, no dependencies. Point an AI at the folder and it has everything it needs: component skills to read, CSS to include, JS to wire up, and this entire documentation site with working examples of every component.

Download latest (.zip)

§Component folder structure

components/
├-- core.css                ← the theme base: tokens + sizing + layout + accessibility
├-- core.js                 ← the runtime: defuss-morph + defuss-query + shared layer
├-- core.min.js             ← minified runtime (same payload all.js embeds first)
├-- all.css                 ← bundle: every component stylesheet (readable)
├-- all.min.css             ← minified bundle
├-- all.min.css.map
├-- all.js                  ← bundle: core runtime + every component's behavior (readable)
├-- all.js.map              ← source map back to the .ts sources
├-- all.min.js              ← minified bundle
├-- all.min.js.map
└-- dialog/
    ├-- component-skill.md  ← HTML structure, attributes, ARIA (read this first)
    ├-- dialog.css          ← stylesheet (include via <link>)
    ├-- dialog.min.css      ← minified stylesheet
    ├-- dialog.js           ← interaction behavior (needs core.js first)
    ├-- dialog.js.map       ← source map for dialog.js
    ├-- dialog.min.js       ← minified behavior
    └-- dialog.min.js.map   ← source map for dialog.min.js

Some components - like Button and Badge - are CSS-only. No JavaScript needed.

§Minified builds & source maps

Every component also ships minified twins, generated at build time with oxc-minify (JS) and Lightning CSS (CSS). Swap the extension to .min.css / .min.js in any URL:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/dialog/dialog.min.css">
<script type="module" src="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/dialog/dialog.min.js"></script>

Minification changes no behavior - the State API (el.api.setState()), globals and data-* attributes work identically. Debugging stays intact: dialog.js.map maps the readable file back to its source and dialog.min.js.map maps the minified file through it; devtools pick both up automatically via sourceMappingURL, so you can set breakpoints in the original source even when loading the .min.js.

The bundle ships the same way: all.min.css (+ all.min.css.map) and all.min.js (+ all.min.js.map) are the minified twins of all.css / all.js - swap them in by URL alone:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/all.min.css">
<script type="module" src="https://cdn.jsdelivr.net/gh/kyr0/defuss-shadcn@latest/dist/components/all.min.js"></script>

Readable and minified files ship from the same source per release, so you can mix them freely - minified in production, readable while developing - and switch back by URL alone.

Comments, ideas or improvements? Edit this page's source on GitHub