Zazz Design Framework
Getting Started

Installation

Add Zazz to any vanilla HTML project in under a minute. No build step required.

Zazz runs on plain CSS and native HTML APIs. No bundler and no framework required. Copy the files, link the stylesheet, write markup.

Download

Grab what you need from the repository. For most projects, copy both folders:

styles is always required. scripts is needed for JS-driven components and behaviors.

Fast copy with degit

Use degit to copy only the directories you need, without cloning the whole repo.

With npm:

npm install -g degit
npx degit dereknelsen/zazz-docs/zazz/styles ./src/zazz/styles
npx degit dereknelsen/zazz-docs/zazz/scripts ./src/zazz/scripts

With pnpm:

pnpm add -g degit
pnpm dlx degit dereknelsen/zazz-docs/zazz/styles ./src/zazz/styles
pnpm dlx degit dereknelsen/zazz-docs/zazz/scripts ./src/zazz/scripts

Need one file only?

pnpm dlx degit dereknelsen/zazz-docs/zazz/styles/ui/_dialog.css ./src/zazz/styles/ui/_dialog.css

If you install individual style files, update your local main.css imports to include them in the right order.

Add a single <link> to your HTML. Point it at main.css; it imports everything in the correct cascade order:

<link rel="stylesheet" href="./zazz/styles/main.css" />

That's it. Every component, token, and utility is now available.

Production: keep main.css, compress on the server

Stick with the single main.css link. CSS this regular compresses extremely well. Turn on brotli or gzip at your host and the whole bundle ships at roughly 10–15% of its raw size, with zero source changes. That's a far bigger win than hand-splitting files, and there's nothing to keep in sync.

<link rel="stylesheet" href="./zazz/styles/main.css" />

A separate <link rel="preload" as="style"> for main.css is not needed. A same-document stylesheet link is already the highest-priority, render-blocking fetch. preload is for late-discovered resources (web fonts, CSS pulled in by JS), not the stylesheet you link in <head>.

You can instead link each _*.css file individually (with preload hints) to avoid main.css's @import chain, but with HTTP/2-3 multiplexing and server compression it's rarely worth the upkeep. If you do, keep the cascade order: base/_layers.css first, then base/_variables.css, base/_reset.css, base/_typography.css, base/_view-transitions.css; the ui/_*.css component files in any order; then base/_utilities.css and base/_layout.css last.

Verify it works

Create an HTML file and add a button:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- Paint the right theme before CSS loads -->
    <meta name="color-scheme" content="light dark" />
    <link rel="stylesheet" href="./zazz/styles/main.css" />
    <title>Zazz Test</title>
  </head>
  <body>
    <button class="button" data-variant="primary">It works</button>
  </body>
</html>

Open it in a browser. If you see a styled button, you're ready.

Project structure

A typical project looks like this:

my-project/
├── index.html
├── zazz/
│   ├── styles/
│   │   ├── main.css                ← entry point (@imports everything)
│   │   ├── base/
│   │   │   ├── _layers.css         ← cascade order (loads first)
│   │   │   ├── _variables.css      ← global design tokens
│   │   │   ├── _reset.css          ← element baselines
│   │   │   ├── _typography.css     ← type system + .prose
│   │   │   ├── _view-transitions.css ← cross-document page transitions
│   │   │   ├── _utilities.css      ← atomic helper classes
│   │   │   └── _layout.css         ← container + layout grid
│   │   └── ui/
│   │       ├── _button.css         ← component styles
│   │       ├── _dialog.css
│   │       └── ...
│   └── scripts/
│       ├── main.js                 ← entry module (imports all scripts)
│       ├── navigation.js           ← page transitions and link handling
│       ├── reveal.js               ← reveal effects
│       └── ...
└── your-styles.css                 ← your overrides (optional)

Customizing

Override any token on :root in your own stylesheet. Load it after main.css:

<link rel="stylesheet" href="./zazz/styles/main.css" />
<link rel="stylesheet" href="./your-styles.css" />
/* your-styles.css */
:root {
  --primary: oklch(0.6 0.2 145);
  --radius-md: 0;
}

Every component that references --primary or --radius-md updates automatically.

Using with a bundler

If you're using Vite, webpack, or esbuild, import main.css directly:

import "./zazz/styles/main.css";

The @import statements resolve at build time. No additional configuration needed.

Next steps

  • Read Overview to understand how the layer system works.
  • Browse Components to see what's available.

On this page