Quick start

Get a styled page running in five minutes — with a CDN script, a bundler plugin, or the standalone CLI.

3 min readv1

Pick the path that matches your project. All three produce the same CSS; they differ only in when it is generated.

Path

Best for

CSS is generated

A · CDN

Prototypes, static pages, CodePen, learning

In the browser, by a 23 kB script

B · Bundler

Vite, Next.js, Nuxt, SvelteKit, Astro, Angular

At build time, into a real .css file

C · CLI

Rails, Django, Laravel, PHP, hand-written HTML

By a command, into nib.css

A · CDN — no build step#

Create an index.html and open it in a browser:

HTML
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <!-- 1. Optional: tokens and component recipes -->
  <script type="application/json" data-nib-config>
    {
      "darkMode": "class",
      "tokens": { "color": { "brand": "#4F52D9" }, "space": { "md": "16px" } },
      "components": {
        "btn": "d=inline-flex; ali=center; g=8px; p=10px $space.md; bdrd=8px; bd=none; cur=pointer; ftw=600; bgc=$color.brand; cl=#fff; hover:bgc=#3A3DBF"
      }
    }
  </script>

  <!-- 2. The runtime. Keep it in <head>, without defer / async / type="module". -->
  <script src="https://cdn.jsdelivr.net/npm/@nibcss/runtime@1"></script>
</head>
<body nib="ftf=system-ui, sans-serif; p=32px; dark:bgc=#0b0f19; dark:cl=#e2e8f0">
  <h1 nib="fts=32px; ftw=800; mb=16px">Hello, NibCSS</h1>
  <button nib="btn" onclick="Nib.toggleDarkMode()">Toggle dark mode</button>
</body>
</html>

That is the whole setup. Elements added later — by your own scripts or by a framework — are styled automatically.

B · Bundler — Vite, Next.js, Nuxt, SvelteKit, Astro#

1. Install the build plugin and the runtime:

Terminal
npm i -D @nibcss/unplugin
npm i @nibcss/runtime

2. Add the plugin to your bundler:

TypeScript
// vite.config.ts — also SvelteKit, Astro, SolidStart, Qwik, Remix
import { defineConfig } from "vite";
import nib from "@nibcss/unplugin/vite";

export default defineConfig({
  plugins: [nib()],
});

3. Import the generated stylesheet once, in your entry file:

TypeScript
// src/main.ts, app/layout.tsx, …
import "@nibcss/styles.css";

4. Create nibcss.config.ts at the project root. The plugin creates a fully commented one on first run if it is missing — replace its body with:

TypeScript
import { defineConfig } from "@nibcss/core";

export default defineConfig({
  darkMode: "class",
  tokens: {
    color: { brand: "#4F52D9", ink: "#0f172a" },
    space: { sm: "8px", md: "16px", lg: "24px" },
  },
  components: {
    btn: "d=inline-flex; ali=center; g=8px; p=8px $space.md; bdrd=8px; cur=pointer; ftw=500",
    "btn-primary": "btn; bgc=$color.brand; cl=#fff; hover:bgc=#3A3DBF",
  },
});

5. Write markup. Every nib="…" in .html, .jsx, .tsx, .vue, .svelte and .astro files is extracted at build time:

TSX
export function Hero() {
  return (
    <section nib="p=48px 24px; txa=center">
      <h1 nib="fts=40px; ftw=800">Ship faster</h1>
      <a nib="btn-primary; mt=16px" href="/start">Get started</a>
    </section>
  );
}

C · CLI — no bundler#

For Rails, Django, Laravel, PHP or plain HTML files:

Terminal
npx @nibcss/cli init    # writes a commented nibcss.config.ts
npx @nibcss/cli build   # scans the project and writes nib.css
npx @nibcss/cli watch   # rebuilds on every change
HTML
<link rel="stylesheet" href="/nib.css" />

<button nib="btn-primary; hover:bgc=#2540b8">Save</button>

Check that it works#

Break something on purpose — write trf=rotate(3deg) instead of tf=…. With debug: true in the config you get:

Text
[nib] src/App.tsx:12:18
  <div nib="trf=rotate(3deg)">
  Unknown utility "trf" — did you mean "t", "tf", "trn"?

No CSS is emitted for an unknown shorthand, so a typo never ships broken styles. More on debugging →

Next steps#