Theming

Every color, radius, and font in Noarka UI is a CSS variable. Override them to re-skin the whole library without forking a single component.

How it works

Two stylesheets carry the theme. tokens.css declares every variable once in :root, and an @theme inline block maps them to Tailwind utilities: --primary becomes bg-primary, --radius-lg becomes rounded-lg, and so on. base.css adds keyframes and small structural styles on top. The @source line registers the library's classes, which Tailwind would otherwise skip inside node_modules.

css
@import "@noarka/ui/styles/tokens.css";@import "@noarka/ui/styles/base.css";@source "../node_modules/@noarka/ui/dist/**/*.js";

Color tokens

The default palette is dark-first. Swatches show the exact shipped values:

TokenSwatchValue
--background

Page background.

oklch(16.9% 0.002 286.2)
--foreground

Default text.

oklch(96% 0.011 286.2)
--card

Card background.

oklch(20.1% 0.002 286.2)
--popover

Dialog and tooltip background.

oklch(20.1% 0.002 286.2)
--surface

Shared popup and menu background.

oklch(22.3% 0.002 286.2)
--secondary

Secondary fills.

oklch(23.1% 0.002 286.3)
--muted

Muted fills and skeleton base.

oklch(23.1% 0.002 286.3)
--accent

Hover and focus fills.

oklch(25.3% 0.004 286.1)
--primary

Brand actions and accents.

oklch(67.4% 0.132 39.1)
--destructive

Danger actions.

oklch(58.6% 0.123 21.5)
--success

Positive status.

oklch(74.6% 0.161 152.4)
--warning

Warning status.

oklch(67.9% 0.077 76.8)
--border

Hairline borders.

oklch(100% 0.00011 271.152 / 0.034)
--input

Input borders.

oklch(23.1% 0.002 286.3)
--ring

Focus rings.

oklch(100% 0.00011 271.152 / 0.034)

Dark mode

The shipped palette is dark, defined once in :root. There is no bundled light theme. A light mode is simply the same variables re-declared with light values:

css
:root {  --background: oklch(1 0 0);  --foreground: oklch(0.148 0.004 228.8);  --card: oklch(1 0 0);  --popover: oklch(1 0 0);  --surface: oklch(0.967 0.001 286.375);  /* ...every other token follows the same pattern. */}

Per-app overrides

Scope variables under a data-theme attribute to theme one app (or one subtree) without touching the rest:

css
[data-theme="acme"] {  --primary: oklch(0.65 0.2 150);}

Radius

One base radius drives the whole scale. Change --radius and every rounded utility follows:

css
:root {  --radius: 0.625rem;  /* sm: -4px · md: -2px · lg: base · xl: +4px */  /* 2xl: +8px · 3xl: +12px · 4xl: +16px */}

Fonts

Three font tokens cover every surface: --font-sans for UI text, --font-serif for display headings, and --font-mono for code. They follow the next/font variable convention, so any variable font can be slotted in:

tsx
import { Geist, Geist_Mono } from "next/font/google";const sans = Geist({ subsets: ["latin"], variable: "--font-sans" });const mono = Geist_Mono({ subsets: ["latin"], variable: "--font-geist-mono" });

Surface

Floating UI shares one background so popups read as a single layer: --surface (#1b1b1c), exposed as bg-surface, text-surface, and border-surface. Menus, tooltips, popovers, sheets, selects, and the dialog footer bands use it; dialog bodies stay on bg-card. Like every token, re-declare it per theme or per app to retint every floating surface at once.

Next steps

Ready to apply this to a project? The installation guide covers importing both stylesheets and the one extra line Tailwind needs.