Clinia UI

How the Theme Works

Clinia UI's theme is built entirely on CSS custom properties. The @clinia/tailwindcss package defines every design token as a CSS variable (e.g., --primary, --background, --radius) and then bridges them into Tailwind v4 utility classes through an @theme inline block:

@theme inline {
  --color-primary: var(--primary);
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --radius-md: var(--radius);
  /* ... */
}

This means that Tailwind utility classes like bg-primary, text-foreground, and rounded-md all resolve to your live CSS variables at runtime. Switching themes or dark mode requires only changing attributes or classes on the <html> element — no JavaScript re-rendering or class toggling on individual components.

Dark Mode

Clinia UI uses a class-based dark mode strategy. Add class="dark" to the <html> element to activate the dark theme:

<html class="dark">

All color tokens have dark-mode overrides defined inside a .dark selector in the theme CSS, so the switch is automatic for every component.

With next-themes

The recommended approach for Next.js apps is to use next-themes, which handles system preference detection, persistence, and hydration:

pnpm add next-themes

Wrap your root layout with the ThemeProvider:

// app/layout.tsx
import { ThemeProvider } from "next-themes"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

The suppressHydrationWarning prop on <html> prevents React from warning about the mismatch between server-rendered and client-resolved theme classes.

Color Tokens

Clinia UI defines semantic color tokens that map to specific roles in the UI. Components reference these tokens by role, not by raw color value, so they adapt automatically across light and dark modes.

CSS Variable Tailwind class Role
--background bg-background Page and surface background
--foreground text-foreground Default text color
--primary bg-primary Primary interactive color (Vital orange)
--primary-foreground text-primary-foreground Text on primary backgrounds
--accent bg-accent Subtle hover and highlight states
--accent-foreground text-accent-foreground Text on accent backgrounds
--destructive bg-destructive Error and danger states
--success bg-success Positive feedback
--warning bg-warning Cautionary feedback
--border border-border Default border color
--muted bg-muted Muted/disabled surface color
--muted-foreground text-muted-foreground Muted text (captions, placeholders)

Customizing Tokens

To override a token, redefine its CSS variable after the @clinia/tailwindcss import in your globals.css:

@import "@clinia/tailwindcss";

:root {
  /* Override the primary color */
  --primary: 210 100% 45%;
  --primary-foreground: 0 0% 100%;
}

.dark {
  --primary: 210 80% 65%;
  --primary-foreground: 210 100% 10%;
}

Color values follow the HSL channel format (H S% L%) without the hsl() wrapper, which matches how shadcn components consume them. Any token defined in @clinia/tailwindcss can be overridden this way.