Skip to main content

Get started

Install LUZ

Pick a level, then copy one install command or the CDN tags. Each level needs the ones below it and nothing above.

LUZ is a place to start, not a finished site. The content, the brand and the final decisions are yours: check the result before you publish.

Know what you are building? Choose your snippet and copy the lines for it, CDN hashes included.

Loading LUZ from a CDN sends your visitors’ IP addresses to the CDN. If you do not want that, install from npm and serve the files from your own server.

Beta
Names, classes and behaviour can still change before the stable release. Pin an exact version, and read the changelog before you upgrade.

Which level do I need?

  • A new project: level 2, tokens and core. luz.css styles the HTML you write.
  • A project that already has a design: level 1, tokens only, to start: it changes nothing you can see. Then level 2 for an existing project, with luz.conditional.css, one region at a time. Migrate a project to LUZ has the steps.
  • Your own components, LUZ’s colours and spacing: level 1, tokens only.
  • Ready-made buttons, forms, tables and dialogs: level 2, tokens and core.
  • Whole pages: shell, page header, footer, search: level 3, the Catalog, all three packages.
  • A landing page, with its header, hero and blocks: level 3 and the patterns for that kind of site, which are catalog components.

Level 1: tokens only

CSS custom properties: the colour, space and type scales, the font roles, the breakpoints and the motion durations, and the colours of light, dark and high contrast. No other LUZ package is needed.

pnpm add @luz-ds/tokens
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/tokens@0.3.0/dist/luz-tokens.min.css">

With a bundler such as Vite, import the files instead of adding tags. A href cannot name a package: these paths are for import only.

Bundler
import "@luz-ds/tokens/css";
  • Running text and headings use ET Book, an MIT-licensed font that ships with the tokens. Controls, labels and tables use the system sans, and code the system mono.
  • Bringing your own fonts? Load dist/tokens.min.css instead: the same tokens without any @font-face.
  • Check your own colours against the WCAG ratios with npx @luz-ds/tokens@0.3.0 check-contrast, or in the browser.

Level 2: tokens and core

The 29 components, the styles of bare HTML elements, and optional JavaScript. Load tokens first.

pnpm add @luz-ds/tokens @luz-ds/core
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/tokens@0.3.0/dist/luz-tokens.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.css">

<!-- Optional: copy buttons, tabs, players, the color mode -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.js"></script>
Bundler
import "@luz-ds/tokens/css";
import "@luz-ds/core/css";

// Optional: copy buttons, tabs, players, the color mode
import "@luz-ds/core";
  • Every page works without the script. See what each JavaScript module adds.
  • Need a single component? Load dist/base.min.css plus the file you want, for example dist/components/button.min.css.
  • Markup you cannot add classes to, such as Markdown or a CMS? A bare button, field or table already has its look in luz.css. On a page that already has a design, load luz.conditional.css instead and mark the zone with data-luz.

Level 2 for a project that already has a design

Load luz.conditional.css instead of luz.css. It is the same file, with the reset and the bare elements limited to the region you mark with data-luz. Load the tokens first, as for any level. From a CDN, link luz.conditional.min.css of @luz-ds/core in place of luz.min.css; with a bundler, import it as below.

Bundler
import "@luz-ds/tokens/css";
import "@luz-ds/core/conditional.css";
  • The element with data-luz takes the font, color and background of the page. The tokens stay on :root.
  • Layout objects, components and utilities are not limited to the region: they apply wherever you put their class.
  • Your old CSS must not be unlayered, or it beats LUZ. Put it in a layer before luz: see Cascade layers and Migrate a project to LUZ.

Level 3, the Catalog: tokens, core and catalog

The site's navigation and the pieces with a script or an identity of their own: navbar, sidebar, terminal, timeline, search, cookie consent, color mode by time of day, language switch, submenu, announcement and FAQ, and the patterns of a kind of site. The catalog needs core and tokens.

The page structure of each kind of site, from the header to the footer, is in the catalog too, one stylesheet per pattern: see Kinds of site.

The catalog has a stylesheet per component: link the ones the page uses, after core.

pnpm add @luz-ds/tokens @luz-ds/core @luz-ds/catalog
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/tokens@0.3.0/dist/luz-tokens.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/search.min.css">

<!-- Optional: core behaviours, and the site search and cookie banner -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/catalog.min.js"></script>
Bundler
import "@luz-ds/tokens/css";
import "@luz-ds/core/css";
import "@luz-ds/catalog/components/search.css";

// Optional: core behaviours, and the site search
import "@luz-ds/core";
import "@luz-ds/catalog";

Kinds of site

To start a landing page, a blog, an app or a documentation site, go to Kinds of site: a prompt for any LLM, and the recipes of each part to copy.

There is no package for a kind of site. Its patterns are components of the catalog, one stylesheet each, named for what the piece is, <block>.css. Install level 3, then link the files your page uses, after core:

  • Landing page: site-header, hero, main, section, stat, site-footer and glow: the header, hero, sections and footer.
  • Blog or newspaper, with any CMS: site-header (or masthead for a newspaper), page-header, article-header, article, post-list and site-footer: the header, page header, article header, contents, post list and footer.
  • Web application: app-bar, dashboard and, for the panels that show data, bar-list, column-chart, stacked-bar, ring and heat-map.
  • Documentation site: docs-layout, doc-header, page-rail, example, do-dont, pager and page-footer.

The catalog has a page for each pattern, and says which kinds of site it fits best.

HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/tokens@0.3.0/dist/luz-tokens.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/site-header.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/hero.min.css">
Bundler
import "@luz-ds/tokens/css";
import "@luz-ds/core/css";
import "@luz-ds/catalog/components/site-header.css";
import "@luz-ds/catalog/components/hero.css";
  • Link the files of a kind in the order of the list above.
  • Link hero with section: the head of a section shares its rules with the hero.
  • None has a script. The catalog's script is optional: with the table of contents of a blog, it marks the section in view; with the sidebar of an app, it marks the current link and closes the drawer when a link is followed. Core's script does not do this.

Before you ship

  • npm and pnpm install the lower levels for you. Yarn only warns, so list every package, as above.
  • On a CDN, pin an exact version and add an integrity hash with crossorigin="anonymous". Compute the hash from the file you load, as below.
  • The core and catalog scripts warn in the console when the level below is missing.
  • Set lang on <html>: core's scripts write their text in that language (English and Spanish ship).
Shell
curl -s https://cdn.jsdelivr.net/npm/@luz-ds/core@0.3.0/dist/luz.min.css | openssl dgst -sha384 -binary | openssl base64 -A

Write the result as integrity="sha384-…" on the tag that loads that file, and repeat it for each file.

A hash on a script covers that file only, not the files it loads later. catalog.min.js loads search.min.js on a page with a search and cookie-consent.min.js on a page with a cookie banner and theme-time.min.js on a page with a time of day for the color mode.

Give each one its own hash in an import map, before the first module script. It works in Chrome 127, Safari 18 and Firefox 138 and later; an older browser ignores it and loads the files unchecked.

A <link rel="modulepreload"> with a hash is not a guard in Safari or Firefox: use it as a performance hint only.

HTML
<script type="importmap">
{
  "integrity": {
    "https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/search.min.js": "sha384-…",
    "https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/cookie-consent.min.js": "sha384-…",
    "https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/theme-time.min.js": "sha384-…"
  }
}
</script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/catalog.min.js" integrity="sha384-…" crossorigin="anonymous"></script>

Next steps

Frequently asked questions

The short answers. Each links to the page that explains it.

What is LUZ?

LUZ is a design system for the web, in three packages: tokens (colors, scales, fonts and three color modes), core (the reset, the style of HTML elements, layout objects, components and optional JavaScript) and the catalog (pieces that act for the whole site, such as search). Use the tokens alone, core with the tokens, or all three. Working with AI shows how an AI can write a site with it.

Are HTML tags styled without a class?

Yes, most of them. Text, links, lists, tables, buttons, form fields, details and dialog come out styled with no class. Tags that only structure the page, such as div, section, header and nav, have no style: the layout is yours. Which elements have a style with no class lists them all.

What are the classes for?

A class adds what HTML cannot say: a link that looks like a button, a role such as danger, a size, a component with markup of its own such as a card, and the layout with the o-* objects. The HTML says the rest: type="button" makes the secondary button, and aria-invalid="true" marks a field with an error. Browse the components to see what each class adds.

Do I need JavaScript?

No. Most components are CSS only, and the ones with a script work without it too. JavaScript modules says what each module adds.

Can I change the default styles?

Yes, without fighting them. Change the tokens to change the whole look, or write your own CSS: CSS with no layer beats every layer of LUZ, with no !important. What you leave alone stays. Changing the default styles shows the three ways.

Is LUZ only for new projects?

No. LUZ fits a new project best, but you can add it to one that already has a design, one region at a time: load luz.conditional.css instead of luz.css and put data-luz on the region. Level 2 for a project that already has a design has the lines to load.

How do I migrate a project to LUZ?

Migrate one page at a time, in five steps: the tokens with your brand, the old CSS in a layer before LUZ, a first region, the other pages one by one, and the old CSS removed. An AI does the mechanical work; you decide and check. Migrate a project to LUZ has the steps.