// documentation

Get started with norcel.

A 5-minute walkthrough. From zero to a working page using every primitive in the kit — with the same dark-first tokens, components, and patterns you see on the marketing site.

5 min readnext.js 16 · react 19typescript · tailwind v4
// 01 · introduction

What is norcel?

A dark-only design system + component library. 34 components, every token exposed as a CSS custom property, every variant typed via CVA. Built so that the marketing site you're looking at is built from the same primitives you'll use.

// benefit

34 components

Buttons, inputs, dialogs, tables, charts, command palette — every primitive you need.

// benefit

Dark by default

Every token is dark-first. Light is opt-in. Polarity-flip when needed.

// benefit

Zero runtime deps

Built on Radix + CVA. Tree-shakeable. ~12 KB gzipped baseline.

// 02 · quickstart

5-minute quickstart

The fastest path from an empty repo to a running page. Run one command, edit one file, ship.

01
// terminal

Bootstrap a new project

Create a new Next.js 16 + Tailwind v4 app. norcel works with any React 19 framework, but the demo assumes Next.js.

bash
npx create-next-app@latest my-app \
  --typescript \
  --tailwind \
  --app \
  --src-dir \
  --import-alias "@/*" \
  --use-npm
cd my-app
02
// terminal

Run the norcel init

Drops the cn() utility, the components.json config, the Tailwind v4 @theme block, and the design tokens into your project. Run this ONCE per project.

bash
npx shadcn@latest add https://ui.norcel.dev/r/init
What this installs
Three files: src/lib/utils.ts, components.json, src/app/theme.css, and it appends the design tokens to your globals.css. Plus 3 npm deps: clsx, tailwind-merge, radix-ui.
03
// terminal

Add components

norcel ships as a set of copy-paste components (not a runtime dependency). The fastest way to grab them is the shadcn registry.

bash
npx shadcn@latest add https://ui.norcel.dev/r/button
npx shadcn@latest add https://ui.norcel.dev/r/card
npx shadcn@latest add https://ui.norcel.dev/r/input
npx shadcn@latest add https://ui.norcel.dev/r/badge
npx shadcn@latest add https://ui.norcel.dev/r/dialog
Or copy individual files
Each component is a single file under src/components/ui/. You can copy any one of them into your project without the registry. See the component catalog for the full list.
04
// src/components/ui/button.tsx

Verify the install

Open src/components/ui/button.tsx in your editor. You should see the full norcel Button source — about 100 lines, importing from @radix-ui/react-slot, class-variance-authority, and @/lib/utils.

bash
cat src/components/ui/button.tsx | head -10
# Output:
# "use client";
#
# import * as React from "react";
# import { Slot } from "@radix-ui/react-slot";
# import { cva, type VariantProps } from "class-variance-authority";
# import { cn } from "@/lib/utils";

If you see the imports + the buttonVariants = cva(...) call, the install worked. If you see a 404 from the registry, check that you ran npm run dev first (or that you deployed with the prebuild hook — see Step 8).

05
// app/layout.tsx

Wrap your app in a dark-first shell

Set `color-scheme: dark` on `<html>` so form controls, scrollbars, and native inputs render in dark. Optional: add the theme provider if you plan to support light mode later.

bash
import type { Metadata, Viewport } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "My App — Built with norcel",
};

export const viewport: Viewport = {
  themeColor: "#0a0a0a",
  colorScheme: "dark",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en" className="dark" style={{ colorScheme: "dark" }}>
      <body className="bg-canvas text-ink">{children}</body>
    </html>
  );
}
06
// app/page.tsx

Compose your first page

Mix marketing + primitives the way the home page does. Each section is a documented component you can copy-paste.

bash
import { Button } from "@/components/ui/button";
import {
  Card, CardHeader, CardTitle, CardDescription, CardContent,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";

export default function Home() {
  return (
    <main className="mx-auto max-w-3xl p-12">
      <Badge>v1.0 — live</Badge>
      <h1 className="mt-6 text-display-xl text-ink">
        Build and ship.
      </h1>
      <p className="mt-4 text-body-lg text-body">
        Welcome to your new norcel app.
      </p>
      <div className="mt-8 flex gap-3">
        <Button size="lg" shape="pill" variant="primary">
          Get started
        </Button>
        <Button size="lg" shape="pill" variant="secondary">
          View docs
        </Button>
      </div>

      <Card className="mt-12">
        <CardHeader>
          <CardTitle>Hello, world.</CardTitle>
          <CardDescription>
            The same primitives, the same tokens, your project.
          </CardDescription>
        </CardHeader>
        <CardContent>
          You just rendered your first card.
        </CardContent>
      </Card>
    </main>
  );
}

Run npm run dev and open http://localhost:3000. You should see a dark hero with a white-pill primary button and a card beneath it — built entirely from the kit.

🎉 You're done
You now have a working norcel app. The next sections go deeper on each piece — tokens, structure, customization.
// 03 · installation

Installation in detail

Three ways to bring norcel into your project. Pick the one that matches your workflow.

// recommended

Via shadcn registry

Run `npx shadcn@latest add <url>` and the file lands in your project. Updates are pull-based.

terminal
npx shadcn@latest add https://ui.norcel.dev/r/button
// manual

Copy a single file

Open the source on GitHub, copy `button.tsx` into `src/components/ui/`, and import it. Zero tooling.

terminal
cp button.tsx src/components/ui/button.tsx
// advanced

Vendor the whole kit

Copy the entire `src/components/ui/`, `src/lib/`, and tokens into your repo. You now own it.

terminal
git clone https://github.com/norcel/ui.git
// 04 · project structure

Where things live

A typical norcel project. The shape is opinionated; the names are not.

my-app/
my-app/
├── app/
│   ├── (auth)/              # auth routes (sign-in, sign-up, …)
│   ├── (marketing)/         # marketing routes (home, pricing, blog)
│   ├── dashboard/           # authenticated app routes
│   ├── layout.tsx           # root layout (html, body, providers)
│   ├── page.tsx             # home / landing
│   └── globals.css           # tokens + base layer
│
├── src/
│   ├── components/
│   │   ├── ui/              # 60+ primitives (button, card, …)
│   │   └── marketing/        # hero, pricing, faq, footer, …
│   │
│   └── lib/
│       ├── utils.ts         # cn() helper
│       └── theme.ts          # design token registry (optional)
│
├── public/
├── package.json
└── tailwind.config.ts
src/components/ui/

Primitives

Every Button, Card, Input, etc. lives here. Each is a single file you can edit freely.

src/components/marketing/

Marketing sections

Hero, Pricing, Testimonials, FAQ, Footer, LogoCloud. Pre-composed sections ready to drop into a page.

app/globals.css

Tokens

Every color, spacing, radius, shadow is a CSS custom property. The single source of truth.

// 05 · configuration

tsconfig + path aliases

Set up path aliases once. The kit uses `@/components/*` and `@/lib/*` everywhere.

tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "strict": true,
    "jsx": "preserve"
  }
}

If you scaffolded with create-next-app --import-alias "@/*", this is already configured. You can skip this step.

// 06 · theming

Customizing the tokens

The fastest way to re-skin norcel. Edit one CSS variable, the whole system updates.

1. Override a color

Drop a new value into globals.css and every component that uses the token updates.

globals.css
:root {
  /* Re-skin the whole system to indigo */
  --color-accent: #818cf8;
  --color-fs-primary: #ffffff;     /* keeps the white pill */
  --color-link: #818cf8;
}

2. Override a radius

Switch from rounded to square by setting --radius-pill to 0px.

globals.css
:root {
  /* Switch to a square look */
  --radius-pill: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;
  --radius-xl: 0px;
}
Want a full token reference?
Every available token is listed on the Colors, Spacing, and Shadows pages. Each shows the live swatch + the underlying CSS variable name.
// 07 · adding components

Adding components to a page

The mental model: marketing sections + primitives. Stack them like Lego.

app/page.tsx
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Hero } from "@/components/marketing/hero";
import { Features } from "@/components/marketing/features";
import { Testimonials } from "@/components/marketing/testimonials";
import { Faq } from "@/components/marketing/faq";
import { Cta } from "@/components/marketing/cta";
import { Footer } from "@/components/marketing/footer";

export default function Home() {
  return (
    <>
      <Hero
        eyebrow="// v1.0 — Live"
        title="Build and ship."
        subtitle="Your new site, using the same primitives as the marketing site."
        primaryCta={{ label: "Get started", href: "/signup" }}
        secondaryCta={{ label: "View pricing", href: "/pricing" }}
      />
      <Features
        title="Everything you need."
        features={[...]}
      />
      <Testimonials testimonials={[...]} />
      <Faq items={[...]} />
      <Cta
        title="Ready to ship?"
        primaryCta={{ label: "Get started", href: "/signup" }}
      />
      <Footer />
    </>
  );
}
// 08 · dark mode patterns

Dark mode by default

norcel is dark-only. Here's how to keep it that way even when browsers / users try to opt in to light.

app/layout.tsx
<html
  lang="en"
  className="dark"           // Tailwind's dark variant
  style={{ colorScheme: "dark" }}  // native form controls
>
  <body className="bg-canvas text-ink">
    {children}
  </body>
</html>

Native form controls

`color-scheme: dark` on `<html>` makes the browser paint date pickers, scrollbars, and input chrome in dark — matching your surface.

OS theme override

If the user has a light OS theme, your app still renders dark. norcel doesn't follow the OS — it asserts the dark canvas.

// 09 · deployment

Ship it

norcel has no runtime server requirements. Deploy anywhere that runs Next.js, Astro, or a static host.

Vercel

Zero config. Push to Git, get a URL.

terminal
vercel --prod

Netlify

Auto-detects Next.js. Edge functions ready.

terminal
netlify deploy --prod

Docker

Standalone Next.js output. ~120 MB image.

terminal
docker build -t app . && docker run -p 3000:3000 app
// you're ready

Build something like this.

You have the tokens, the components, and the patterns. The home page, pricing, FAQ, testimonials, CTA — all of it is the kit, wired together. Now go wire your own.