Kajabi Admin Dark Mode

Dark mode as platform architecture, not a visual skin.

In 2026, Kajabi released dark mode for its admin experience. The feature looked simple from the outside, but the work behind it exposed hidden design system debt across Rails, React, Sage, TinyMCE, Pine, and multiple generations of product UI.

Overview

Users saw a toggle. The platform needed a theme system.

The Design Systems team treated dark mode as infrastructure. My role focused on the architectural patterns, semantic token adoption, migration strategy, and implementation details that let dark mode scale across a decade-old admin platform.

Core idea

The challenge was not creating dark colors. The challenge was helping every surface understand what those colors meant.

Before / After Impact

Dark mode revealed where the product already lacked a shared styling contract.

A second theme made disconnected color decisions visible. Hardcoded values, legacy components, embedded editors, and third-party assumptions all became part of the same systems problem.

  • Dark mode support across Kajabi Admin
  • A shared theme contract for Rails, React, Pine, Sage, and embedded surfaces
  • A migration path away from hardcoded color values
  • A reusable pattern for iframe-based editor theming
  • A foundation for future theme capabilities
LightKajabi Admin dashboard in light mode with navigation, analytics cards, and promotional cards.
DarkKajabi Admin dashboard in dark mode with the same navigation, analytics cards, and promotional cards.
Admin dashboard in light and dark mode. The paired view shows dark mode affecting product navigation, analytics cards, charts, empty states, CTAs, and supporting surfaces together.

Theme Architecture

A single root-level theme contract kept the platform from fragmenting.

The key architectural decision was using one source of truth for theme state instead of letting each app, surface, or component family manage theme independently.

Shared contract

<html data-theme="dark">
  • Rails views
  • React applications
  • Pine components
  • Sage and legacy UI
  • TinyMCE iframes

Independent theme management would have created competing sources of truth, inconsistent persistence, and duplicated implementation logic. The root contract gave every surface the same signal.

Root theme contractOne root attribute became the shared signal for theme-aware surfaces.
<html data-theme="dark">
  • Rails views

    Server-rendered surfaces read the same contract.

  • React apps

    Product experiences resolve theme state consistently.

  • Pine components

    Design system UI renders with semantic tokens.

  • Sage bridge

    Legacy surfaces participate during migration.

  • TinyMCE

    Embedded editors receive mirrored theme state.

Semantic Token Strategy

Before dark mode could scale, color needed product meaning.

Semantic tokens moved theme behavior out of individual CSS decisions and into a shared design system language.

The important shift was not visual. It was moving from direct color declarations to tokens that describe product intent. Once surfaces used semantic tokens, light and dark themes could resolve through the same implementation path.

Before

Hardcoded values made theme behavior a local styling problem.

background: #ffffff;
color: #222222;

After

Semantic tokens made theme behavior a system contract.

background: var(--pine-color-background-container);
color: var(--pine-color-text);

Legacy Compatibility & Migration

Legacy systems had to participate before they could be replaced.

Large parts of Kajabi Admin still depended on Sage, older color systems, Rails views, and inherited styling. Waiting for a full rewrite would have made dark mode impractical.

Legacy surface

Rails, Sage, older color systems, and inherited product styles.

Compatibility layer

Mapping and migration patterns connected old surfaces to theme intent.

Pine theme contract

Semantic tokens and shared theme state enabled consistent behavior.

This was the adoption work underneath the feature: helping teams move away from hardcoded color values and into a modern theme architecture without stopping product delivery.

LightKajabi offer details page in light mode showing forms, status cards, and TinyMCE editor.
DarkKajabi offer details page in dark mode showing forms, status cards, and TinyMCE editor.
A transitional product surface in both themes. This view is useful because it shows real migration conditions: form controls, status chips, rich text editing, cards, and legacy-era surfaces participating in the same theme.

TinyMCE & Embedded Systems

TinyMCE turned dark mode into a cross-document theming problem.

The editor rendered inside an iframe. That meant it operated as a separate document and could not automatically inherit CSS variables or theme state from the parent app.

Problem
Iframes cannot automatically access the parent document's theme state or CSS variables.
Decision
Mirror theme state into the editor environment and maintain dedicated editor styles.
Outcome
The pattern became reusable for embedded experiences that need to participate in platform theming.
LightTinyMCE editor in light mode with toolbar and editable content.
DarkTinyMCE editor in dark mode with toolbar and editable content.
TinyMCE editor content in light and dark mode. The editor proves the iframe problem: toolbar chrome, editable content, borders, and text colors all needed to respond even though the editor runs in a separate document.

Rollout Strategy

Feature flags and preference handling reduced organizational risk.

The rollout had to protect creator preferences, support internal testing, and work with account masquerading without accidentally changing someone else's theme state.

  • Released behind a feature flag
  • Persisted creator theme preferences across sessions
  • Protected preferences during account masquerading workflows
  • Created space for validation before broad rollout
Rollout and preference modelDark mode shipped through separated release, preference, session, and render concerns.
  1. 1Feature flag

    Control availability for internal testing and gradual release.

  2. 2User preference

    Persist the creator's light or dark mode choice across sessions.

  3. 3Session context

    Respect workflows like masquerading without overwriting creator state.

  4. 4Theme render

    Apply the root theme contract across app, design system, and embedded surfaces.

Outcomes

Dark mode became a platform capability.

The work created a scalable theming architecture, improved the migration path for legacy UI, reduced reliance on hardcoded color values, and gave future teams a foundation for theme-aware product development.

  • Dark mode support across Kajabi Admin
  • A shared theme contract for Rails, React, Pine, Sage, and embedded surfaces
  • A migration path away from hardcoded color values
  • A reusable pattern for iframe-based editor theming
  • A foundation for future theme capabilities

Reflection

Dark mode revealed the design system work underneath.

The biggest lesson from this project is that dark mode is not really a dark mode project. It is a design systems project. Features like dark mode expose every inconsistency hiding within a platform.

Dark mode did not create the technical debt. It revealed it.

Most people will not think about semantic tokens, theme contracts, compatibility layers, or iframe styling strategies. They will notice that dark mode works. That is the point. The best design system work often disappears into the product.