npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cooud-ui/theme

v0.5.0

Published

Cooud runtime theming engine — CooudUIProvider + useTheme (CSS-var only, no re-render).

Readme

@cooud-ui/theme

The Cooud UI runtime theming engine — a React provider and hook that apply @cooud-ui/tokens to your app and let you re-theme any subtree live.

Theming happens entirely through CSS custom properties: switching theme, toggling light/dark, or overriding a token (radius, primary, border, …) updates the whole subtree instantly without re-rendering the components below it. This is what makes brand portals, per-tenant styling, and visual preview builders cheap.

You need this package if you render @cooud-ui/ui components and want runtime theme control, mode switching, or token overrides. (It is also the only supported way to inject the --cooud-* variables when running on Tailwind v3.)

Install

Published on npm under the @cooud-ui scope.

# npm
npm i @cooud-ui/theme @cooud-ui/tokens
# pnpm
pnpm add @cooud-ui/theme @cooud-ui/tokens
# bun
bun add @cooud-ui/theme @cooud-ui/tokens

Prerequisites

  • React 19 (also works with React 18.3+) — react and react-dom are peer dependencies.
  • @cooud-ui/tokens — the token data this provider applies (installed alongside above; on Tailwind v4 also import @cooud-ui/tokens/styles.css once).

Usage

Wrap your app at the framework root. Use asRoot so the theme/mode attributes are written to <html> and the whole document is themed.

// app/layout.tsx (Next.js App Router) — or your root component
import "@cooud-ui/tokens/styles.css";
import { CooudUIProvider } from "@cooud-ui/theme";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <CooudUIProvider asRoot defaultThemeName="aurora" defaultModeName="dark">
          {children}
        </CooudUIProvider>
      </body>
    </html>
  );
}

Avoiding a flash of the wrong theme

When you use asRoot with a storageKey, the provider restores the saved theme/mode from localStorage in an effect that runs after first paint — so a returning visitor whose saved choice differs from the defaults briefly sees the default theme before it swaps (a "flash of the wrong theme", or FOUC).

Render <CooudThemeScript> in your document <head> to apply the saved theme/mode before paint. It emits one tiny inline script that reads the same storageKey and sets the data-cooud-theme / data-cooud-mode attributes and the dark class on <html> exactly as the provider does.

// app/layout.tsx (Next.js App Router)
import { CooudThemeScript, CooudUIProvider } from "@cooud-ui/theme";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    // suppressHydrationWarning: the script mutates <html> before React hydrates.
    <html lang="en" suppressHydrationWarning>
      <head>
        <CooudThemeScript
          storageKey="cooud-ui-theme"
          defaultThemeName="aurora"
          defaultModeName="dark"
        />
      </head>
      <body>
        <CooudUIProvider asRoot storageKey="cooud-ui-theme">
          {children}
        </CooudUIProvider>
      </body>
    </html>
  );
}

Pass the same storageKey to both the script and the provider. Add suppressHydrationWarning to <html> because the script changes those attributes before hydration; without it React logs a hydration mismatch. For a strict CSP, pass a nonce to <CooudThemeScript nonce={nonce} />.

useTheme

Read and control the active theme from anywhere inside the provider.

"use client";
import { useTheme } from "@cooud-ui/theme";

export function ThemeControls() {
  const { theme, mode, setTheme, setMode, toggleMode, setOverrides } = useTheme();

  return (
    <div>
      <button onClick={toggleMode}>Mode: {mode}</button>
      <button onClick={() => setTheme(theme === "aurora" ? "neutral" : "aurora")}>
        Theme: {theme}
      </button>
      {/* Re-theme the whole subtree at runtime — no component re-render: */}
      <button
        onClick={() =>
          setOverrides({
            radius: "16px",
            primary: "oklch(0.685 0.169 237.3)",
            fontDisplay: "Inter, sans-serif",
          })
        }
      >
        Apply brand theme
      </button>
    </div>
  );
}

Calling useTheme() outside a <CooudUIProvider> throws.

API

<CooudUIProvider>

| Prop | Type | Default | Description | | ------------------ | ---------------- | ---------- | --------------------------------------------------------------------------- | | defaultThemeName | ThemeName | "aurora" | Initial theme ("aurora" | "neutral"). | | defaultModeName | Mode | "dark" | Initial mode ("light" | "dark"). | | overrides | ThemeOverrides | — | Seed per-scope token overrides (initial value only; later use setOverrides). | | asRoot | boolean | false | Write attributes to <html> (whole document) instead of a wrapper <div>. | | storageKey | string | — | Persist the theme/mode choice to localStorage under this key. | | className | string | — | Extra classes for the wrapper <div> (ignored when asRoot). |

When asRoot is false, the provider renders a <div> that themes only its subtree — useful for previews and isolated brand sections.

overrides is reactive: change its content (e.g. from a controlled parent) and the themed element updates. A re-render that passes a new object of equal content does not loop or reset live overrides. setOverrides from useTheme still drives uncontrolled changes.

<CooudThemeScript>

Inline anti-FOUC head script (see Avoiding a flash of the wrong theme).

| Prop | Type | Default | Description | | ------------------ | ----------- | ---------- | ----------------------------------------------------------------- | | storageKey | string | — | Required. The same key passed to <CooudUIProvider storageKey>. | | defaultThemeName | ThemeName | "aurora" | Theme applied when storage is empty or unreadable. | | defaultModeName | Mode | "dark" | Mode applied when storage is empty or unreadable. | | nonce | string | — | CSP nonce forwarded to the inline <script>. |

useTheme(): ThemeContextValue

Returns { theme, mode, overrides, setTheme, setMode, toggleMode, setOverrides }. ThemeName, Mode, and ThemeOverrides come from @cooud-ui/tokens.

How it works

overrides are converted to a { "--cooud-*": value } style object (via @cooud-ui/tokens) and set on the themed element; the @cooud-ui/tokens Tailwind bridge maps utilities like bg-primary and rounded-lg onto those variables. Because everything resolves through CSS variables, overriding a token restyles the subtree with no React re-render of the components it contains.

Related packages

License

MIT