Skip to content

Repository files navigation

react-tenant-theme

A lightweight, production-ready theming engine for multi-tenant React applications.

TypeScript React License

Docs: Live documentation & examples · npm: react-tenant-theme


✨ Why This Exists

Modern SaaS applications often require:

  • Multi-tenant branding
  • Light/Dark mode per tenant
  • Scalable design token systems
  • SSR compatibility
  • Zero visual flicker on reload

Most theming solutions become fragile at scale.

react-tenant-theme provides a clean, architecture-first approach to solving this problem using CSS variables and a structured tenant → theme → token model.


🔑 Key Features

  • ✅ Multi-tenant support
  • ✅ Per-tenant theme switching
  • ✅ Type-safe token definitions
  • ✅ CSS variable-based design tokens
  • ✅ SSR-safe (Next.js compatible)
  • ✅ No flash of default theme
  • ✅ LocalStorage persistence
  • ✅ Minimal runtime overhead

📦 Installation

npm install react-tenant-theme
# or
pnpm add react-tenant-theme
# or
yarn add react-tenant-theme

🚀 Quick Start

1️⃣ Define Tenants & Themes

import type { TenantDefinition } from "react-tenant-theme";

const tenants: TenantDefinition[] = [
  {
    id: "acme",
    name: "Acme Inc",
    defaultThemeId: "light",
    themes: [
      {
        id: "light",
        name: "Light",
        tokens: {
          "color-bg": "#ffffff",
          "color-fg": "#111111",
          "color-primary": "#2563eb"
        }
      },
      {
        id: "dark",
        name: "Dark",
        tokens: {
          "color-bg": "#0b1020",
          "color-fg": "#e5e7eb",
          "color-primary": "#60a5fa"
        }
      }
    ]
  }
];

2️⃣ Wrap Your Application

import { ThemeProvider } from "react-tenant-theme";

<ThemeProvider
  tenants={tenants}
  initialTenantId="acme"
  config={{ prefix: "rt" }}
>
  <App />
</ThemeProvider>

3️⃣ Use the Hook

import { useThemeEngine } from "react-tenant-theme";

const { tenant, theme, setTenant, setTheme } = useThemeEngine();

🎨 Styling with CSS Variables

The library generates scoped CSS variables:

body {
  background: var(--rt-color-bg);
  color: var(--rt-color-fg);
}

button {
  background: var(--rt-color-primary);
}

Switching tenant or theme updates all tokens instantly.


🏗 Architecture Overview

react-tenant-theme is structured into three layers:

1️⃣ Tenant Layer

Represents a SaaS customer or brand.

2️⃣ Theme Layer

Represents visual variants (light, dark, brand).

3️⃣ Token Layer

Maps tokens to scoped CSS variables:

color-primary → --rt-color-primary

The runtime engine:

  • Validates tenant/theme relationships
  • Applies tokens safely
  • Persists user preferences
  • Prevents hydration mismatches

⚡ SSR & Hydration Safety

  • Uses an isomorphic layout effect
  • Hydrates before first paint
  • Avoids flash-of-default-theme
  • Safe for Next.js / Vite SSR

💾 Persistence Strategy

Saved to:

localStorage["react-tenant-theme"]

Format:

{
  "tenantId": "acme",
  "themeId": "dark"
}

🧠 Real-World Use Cases

  • White-label SaaS dashboards
  • Enterprise admin panels
  • Multi-brand B2B platforms
  • Internal enterprise tools
  • Client-customizable UI systems

🛣 Roadmap

  • Configurable storage key
  • Cookie-based persistence
  • Pre-hydration inline script
  • DevTools extension
  • Tailwind plugin integration
  • Token validation utilities

🛠 Development

From the repo root after clone or pull, install dependencies then build or run the docs:

pnpm install
pnpm build          # build all workspace packages
pnpm dev:docs       # run the docs app (apps/docs)
pnpm dev:core       # run theming-engine in watch mode

🤝 Contributing

Contributions welcome.

  1. Fork the repo
  2. Create a branch
  3. Submit a PR

📄 License

MIT


🧩 Author

Built to address real-world multi-tenant theming challenges in scalable React applications.

Releases

Packages

Contributors

Languages