Skip to content

Type to search the docs, API, and blog.

↑↓ navigate↵ openesc close
Zazz 0.7 alpha
Docs navigation

Docs

Editor and linting

The VS Code extension, the ESLint plugin, <ui-debug>, and custom data for other editors.

The same audit runs in four places: the browser console (<ui-debug>), the editor (the language server), the command line (the ESLint plugin), and the commit hook. They share one implementation, audit-core.ts in the kit, so they report the same finding on the same range.

<ui-debug>

Development only. Add it to the page body and it audits every element's style and data-* attributes once, then again on each mutation, logging [ui-debug] warnings: an unknown utility, a wrong value mode, a tier without a base, a modifier the family lacks, a utility that flattens a state a hook covers, a raw property shadowing a utility, a whitespace form the gates cannot match (--w : 4, or --w:auto where the value is matched as text), and a data-<name>-* attribute outside its identity. It also lists the elements persisted across navigations and flags misuse.

<ui-debug data-debug-domains="localhost, staging.example.com"></ui-debug>

On a hostname not in the list it removes itself and logs once, so it can ship in a template without reaching production users. It reads identities and hooks from the page's own stylesheets, so it needs no manifest and works with a partial vendored kit.

The playground runs both inside its editor: findings appear as Monaco markers, Shift+Alt+F applies the same formatter, pasted markup is formatted on paste, and ⌘S / Ctrl+S formats and re-renders.

VS Code and Cursor

The Zazz extension runs the kit's code in a language server. It is not on the Marketplace yet; build it from the repo and install the .vsix:

vp run zazz-vscode#package
code --install-extension packages/vscode/dist/zazz.vsix
FeatureWhat you get
Diagnosticsthe <ui-debug> audit as you type, plus a note when the head block does not load a primitive the page uses
Completionsutility names, then only the tiers a utility takes; --group- and pseudo forms; hooks for the identities in reach; values with resolved tokens; data-ui identities, presets, and ui-* tags
Hover and inlay hintswhat a utility sets and when its tier applies; --p: 4 ≈ 0.9–1rem; --px--md ≥ 48rem; a token's resolved value; a hook's default
Formattingsource.fixAll.zazz on save writes every style in cascade order, one utility per line
Code actionsquick fixes from the audit; Organize imports sorts kit stylesheets into cascade order
Auto-importson a page with a <!-- zazz:head {…} --> block, completing an identity adds its primitive to the head
Highlightingutility families, tiers, prefixes, hooks, identities; color swatches before var(--color-*)
Snippets and Emmetzazz-<example> for every kit example; ui-card>h2 with the repo's emmet.extensionsPath
TemplatesZazz: New page…: blank, from a primitive, swap-navigation, or a primitive fragment

Settings: zazz.languages, zazz.diagnostics.enable, zazz.inlayHints.enable, zazz.colorSwatches.enable, zazz.templates.base. Add "source.fixAll.zazz": "explicit" to editor.codeActionsOnSave.

Templating languages

The features run in plain HTML by default. Add a language id to zazz.languages and they run in that language's files too: the server masks the language's own expressions before parsing, so {expr}, <%= %>, @Model.Name, and {{ name }} are never read as markup or as CSS, and nothing inside them is reported, completed, or reformatted.

{ "zazz.languages": ["html", "astro", "razor", "erb", "phoenix-heex"] }

Known ids: astro, vue, svelte, razor / aspnetcorerazor, asp / aspx, erb, php, phoenix-heex / html-eex / eex, elixir (the ~H sigils), handlebars, mustache, twig, jinja / jinja-html, nunjucks, liquid, django-html, blade. Markup inside an Astro expression ({items.map((i) => <li>…</li>)}) is still audited. JSX and TSX are not on the list: style is an object there, not a string, so the utilities would need a different parser. React and Vue also serialize an object style without the space after the colon, which matters for keyword values; the utilities overview has the workaround.

Other editors

The language server speaks standard LSP over stdio (node packages/vscode/dist/server.cjs --stdio after vp run zazz-vscode#build), but it is not yet published as a standalone package or documented for Neovim, Zed, or Helix. Until it is, the kit ships VS Code custom-data files that any editor supporting the format can load for flat completions: editor/zazz.html-data.json (tags, data-ui tokens, every data-<name>-* attribute with its values) and editor/zazz.css-data.json (every utility, tier, and hook).

{
  "html.customData": ["./zazz/editor/zazz.html-data.json"],
  "css.customData": ["./zazz/editor/zazz.css-data.json"]
}

ESLint

@zazz-ui/eslint-plugin wraps the audit as rules for the html-eslint language, one rule per finding plus style-format, the fixable formatter (cascade order, one utility per line, --px:6 normalized to --px: 6).

// eslint.config.ts
import html from "@html-eslint/eslint-plugin";
import { defineConfig } from "eslint/config";
import zazz from "@zazz-ui/eslint-plugin";

export default defineConfig([
  {
    files: ["**/*.html"],
    plugins: { html },
    language: "html/html",
    extends: [zazz.configs.recommended],
    rules: { "zazz/style-format": "error" },
  },
]);

configs.recommended sets a rule to error when the finding means the declaration does nothing at all (an unknown utility, a tier the family has no setter for or that has no base, a pseudo or group form the utility lacks, and a whitespace form the gates cannot match), and the rest to warn. Run it with eslint "**/*.html"; eslint --fix applies the formatter. In this repo that is vp run lint:html and vp run fmt:html, and the staged-files hook formats HTML on commit. The plugin is private to the monorepo for now.