HTML & CDN
Use NibCSS on any HTML page with one script tag — no build tools, no npm, no framework.
The shortest possible setup: one script tag on a page. The runtime scans the document, resolves every
nib attribute it finds, and keeps watching for elements added later — including markup your own
scripts inject.
This is the right choice for a landing page, a prototype, an email-style template, or any page that is not built by a bundler. When you want the classes compiled into the HTML instead, move on to the CLI — same config, same output, no runtime needed.
The one-tag version#
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/@nibcss/runtime"></script>
</head>
<body nib="m=0; ftf=system-ui; p=40px; bgc=#f8fafc; dark:bgc=#0b0f19">
<h1 nib="fts=32px; ftw=800; cl=#0f172a; dark:cl=#f8fafc">Hello, nib</h1>
<button nib="p=10px 18px; bdrd=8px; bd=none; bgc=#4f46e5; cl=#fff; ftw=600; cur=pointer; hover:bgc=#4338ca">
Click me
</button>
</body>
</html>With your own config#
Tokens, recipes, a custom prefix and dark mode belong in a config. On a page with no build step,
hand it to the runtime with a plain script — before the runtime tag:
<head>
<script>
window.__NIB__ = {
darkMode: "class",
tokens: {
color: { brand: "#4f46e5", ink: "#0f172a", surface: "#ffffff" },
radius: { sm: "8px", md: "12px" },
},
components: {
btn: "d=inline-flex; ali=center; g=8px; p=10px 18px; bdrd=$radius.sm; bd=none; bgc=$color.brand; cl=#fff; ftw=600; cur=pointer",
},
};
</script>
<script src="https://cdn.jsdelivr.net/npm/@nibcss/runtime"></script>
</head>
<button nib="btn">Save</button>What the runtime does on the page#
Step | |
|---|---|
1 | reads |
2 | scans the document for |
3 | writes the rules it needs into its own |
4 | watches the DOM, so anything added later is styled too |
Scoped to part of a page#
Embedding a widget into someone else's page? Give it its own runtime so your rules and theirs never collide:
<script type="module">
import { NibRuntime } from "https://cdn.jsdelivr.net/npm/@nibcss/runtime/+esm";
const widget = document.querySelector("#my-widget");
const rt = new NibRuntime({ root: widget, prefix: "wgt-", tokens: { color: { brand: "#10b981" } } });
</script>The browser API#
The global runtime is window.Nib:
Member | What it is |
|---|---|
| the class string for an attribute, with its CSS inserted |
| the |
| change tokens, recipes or |
| the resolved config, as the browser has it |
| rule and class counts |
| apply what the observer has queued, right now |
| the class, for a second instance scoped to a subtree |
<div nib="d=flex; g=10px; ali=center; p=14px; bdrd=12px; bgc=#eef2ff; dark:bgc=#1e1b4b">
<span nib="w=10px; h=10px; bdrd=999px; bgc=#4f46e5"></span>
<span nib="fts=14px; ftw=600">Styled by the runtime, no build step</span>
</div>Common pitfalls#
defer/async/type="module"on the runtime tag — the page paints unstyled first.- A custom
prefixin the config but not in the browser: nothing on the page matches the stylesheet. - Expecting
class="btn"to work — a recipe name is only a recipe insidenib, or throughNib.classesFor("btn"). - Hand-written
window.__NIB__drifting fromnibcss.config.ts— generate it with the CLI instead.