Skip to content

Design Token Adoption & App Color Strategy

Dashboard components across MemberJunction Explorer hardcode hex colors — over 60 files with 100+ unique hex values. This creates visual inconsistency (different blues, different grays across apps) and breaks theming (hardcoded colors don’t respond to light/dark mode).

Per the Feb 3, 2025 UX design meeting, the team decided:

  • App colors are nav wayfinding only — top nav buttons, tab indicators. They do NOT extend into dashboard content.
  • All dashboard content uses the unified MJ token system — same colors everywhere, regardless of which app you’re in.
  • No per-app content theming — avoids the “rainbow effect” and keeps the product feeling unified.

This guide serves as the team reference for the design token system. Kendo UI has been fully removed — all components now use @memberjunction/ng-ui-components with --mj-* semantic tokens.


  1. App Color Scope — Nav Wayfinding Only
  2. Token Adoption Decision Guide
  3. Chart & Data Visualization Colors
  4. Category/Type Colors
  5. Migration Inventory
  6. Partially Migrated Files
  7. Shared Patterns File Reference
  8. Legacy Variable Cleanup
  9. What NOT to Do

1. App Color Scope — Nav Wayfinding Only

Section titled “1. App Color Scope — Nav Wayfinding Only”

The Application.Color field drives --app-color, which is set per-element via [style.--app-color] bindings in the shell template. Its scope is strictly limited to navigation chrome:

Where app color IS usedWhere app color is NOT used
Top nav bar app buttons (hover/active state)Dashboard cards, panels, backgrounds
Active tab left-edge indicatorPrimary action buttons
Active nav item background/text/iconChart colors or data visualizations
Tab active glowStatus badges (success/error/warning)
KPI card borders or accents
Any content inside a dashboard

Files that consume --app-color (exhaustive list):

FileUsage
explorer-core/.../shell/shell.component.cssNav bar app button hover/active/indicator
explorer-core/.../shell/components/header/app-nav.component.cssActive nav item background/text/icon
explorer-core/.../shell/components/tabs/tab-container.component.cssTab left-edge indicator and active glow

Why app colors don’t flow into content:

  • Brand color collisions — A red-themed app would make danger buttons and error states visually ambiguous. Is that red button a delete action or just the app’s brand?
  • Visual unity — Users switch between apps frequently. If every app had its own content palette, the product would feel like a collection of disconnected tools rather than one unified platform.
  • Theming compatibility — The token system supports light/dark mode and custom themes. Per-app content colors would need N x M variants (apps x themes), creating an unsustainable maintenance burden.
  • Accessibility — Contrast ratios are validated against the token system’s known palette. Random app colors could break WCAG compliance in content areas.

Every hardcoded color in dashboard CSS or TypeScript should be replaced with a semantic MJ token. Use this table to find the right one:

PatternTokenNotes
Primary action buttonsvar(--mj-brand-primary)The standard MJ blue
Button text on primary bgvar(--mj-brand-on-primary)White on dark, dark on light
Button hovervar(--mj-brand-primary-hover)
Button active/pressedvar(--mj-brand-primary-active)
Secondary actionsvar(--mj-brand-tertiary)Cyan/teal family
Accent highlightsvar(--mj-brand-accent)Light blue family
Linksvar(--mj-text-link)
Link hovervar(--mj-text-link-hover)

Each status has four tokens for different contexts:

PatternBase TokenBackgroundTextBorder
Success states--mj-status-success--mj-status-success-bg--mj-status-success-text--mj-status-success-border
Error/danger states--mj-status-error--mj-status-error-bg--mj-status-error-text--mj-status-error-border
Warning states--mj-status-warning--mj-status-warning-bg--mj-status-warning-text--mj-status-warning-border
Info states--mj-status-info--mj-status-info-bg--mj-status-info-text--mj-status-info-border
PatternToken
Page backgroundvar(--mj-bg-page)
Card backgroundsvar(--mj-bg-surface-card)
Panel/dialog backgroundsvar(--mj-bg-surface)
Elevated surfaces (dropdowns, popovers)var(--mj-bg-surface-elevated)
Sunken/inset areasvar(--mj-bg-surface-sunken)
Hover backgroundsvar(--mj-bg-surface-hover)
Active/pressed backgroundsvar(--mj-bg-surface-active)
Modal overlay backdropvar(--mj-bg-overlay)
PatternToken
Primary body text (#1e293b, #333)var(--mj-text-primary)
Secondary/supporting text (#666, #475569)var(--mj-text-secondary)
Muted/de-emphasized text (#999, #64748b)var(--mj-text-muted)
Disabled textvar(--mj-text-disabled)
Text on dark backgrounds (#fff)var(--mj-text-inverse)
PatternToken
Standard borders (#e0e0e0, #e0e6ed)var(--mj-border-default)
Subtle/light borders (#f0f0f0, #e5e7eb)var(--mj-border-subtle)
Emphasized bordersvar(--mj-border-strong)
Focus ringvar(--mj-border-focus)
Error bordersvar(--mj-border-error)
PatternToken
Small shadowvar(--mj-shadow-sm)
Medium shadowvar(--mj-shadow-md)
Large shadowvar(--mj-shadow-lg)
Extra-large shadowvar(--mj-shadow-xl)
Brand-colored shadowvar(--mj-shadow-brand-sm), var(--mj-shadow-brand-md)

These are the most frequently hardcoded hex values found in the codebase and their token replacements:

Hardcoded HexApprox. NameReplace With
#6366f1Indigovar(--mj-brand-primary) for actions, or primitive var(--mj-color-indigo-500) for decorative
#8b5cf6Purplevar(--mj-brand-accent) for accents, or var(--mj-color-violet-500) for decorative
#2196f3, #3b82f6Bluevar(--mj-brand-primary) for actions, var(--mj-status-info) for info states
#10b981, #4caf50Greenvar(--mj-status-success)
#f59e0b, #ff9800Ambervar(--mj-status-warning)
#ef4444, #f44336, #d32f2fRedvar(--mj-status-error)
#06b6d4, #00bcd4Cyanvar(--mj-brand-tertiary)
#ec4899Pinkvar(--mj-highlight)
#1e293b, #333Dark slatevar(--mj-text-primary)
#475569, #666Medium grayvar(--mj-text-secondary)
#64748b, #999Muted grayvar(--mj-text-muted)
#e0e0e0, #dddLight gray bordervar(--mj-border-default)
#f5f7fa, #f8f9faLight backgroundvar(--mj-bg-surface-card)
#fff, #ffffffWhitevar(--mj-bg-surface) or var(--mj-text-inverse) depending on context

Charts need multiple distinct colors for series. These should never be derived from app colors. Use the following approach:

Semantic Series (Preferred When Applicable)

Section titled “Semantic Series (Preferred When Applicable)”

When chart series have inherent meaning, use status tokens:

// Success rate chart, error rate chart, etc.
const semanticColors = {
success: getComputedStyle(root).getPropertyValue('--mj-status-success').trim(),
warning: getComputedStyle(root).getPropertyValue('--mj-status-warning').trim(),
error: getComputedStyle(root).getPropertyValue('--mj-status-error').trim(),
info: getComputedStyle(root).getPropertyValue('--mj-status-info').trim(),
};

Non-Semantic Series (Arbitrary Data Categories)

Section titled “Non-Semantic Series (Arbitrary Data Categories)”

When chart series are arbitrary (model comparison, time-based breakdown, etc.), use the brand token family:

const seriesColors = [
getComputedStyle(root).getPropertyValue('--mj-brand-primary').trim(),
getComputedStyle(root).getPropertyValue('--mj-brand-accent').trim(),
getComputedStyle(root).getPropertyValue('--mj-brand-tertiary').trim(),
getComputedStyle(root).getPropertyValue('--mj-color-indigo-500').trim(),
getComputedStyle(root).getPropertyValue('--mj-color-violet-500').trim(),
];

For components that need multiple token values (common in chart libraries), use a helper method:

private getTokenValue(token: string): string {
return getComputedStyle(document.documentElement)
.getPropertyValue(token).trim();
}
// Usage
const colors = [
this.getTokenValue('--mj-brand-primary'),
this.getTokenValue('--mj-brand-accent'),
this.getTokenValue('--mj-brand-tertiary'),
];

Future Consideration: Chart Palette Tokens

Section titled “Future Consideration: Chart Palette Tokens”

If the existing tokens prove insufficient for complex multi-series charts (8+ series), a dedicated --mj-chart-* palette could be defined in _tokens.scss. For now, combining brand + status + primitive tokens covers all current use cases.


Several dashboards assign colors to categories — API scope types, credential categories, component types, operation types. These are decorative, not semantic — the color doesn’t convey meaning, it just helps distinguish items visually.

Instead of hardcoding hex values, use a fixed rotation of MJ primitive color tokens:

const CATEGORY_PALETTE: string[] = [
'var(--mj-color-brand-500)', // Blue
'var(--mj-color-accent-500)', // Light blue
'var(--mj-color-tertiary-500)', // Cyan
'var(--mj-color-indigo-500)', // Indigo
'var(--mj-color-violet-500)', // Purple
'var(--mj-color-success-500)', // Green
'var(--mj-color-warning-500)', // Amber
'var(--mj-color-error-500)', // Red
];
// Assign colors by index, cycling if more categories than colors
function getCategoryColor(index: number): string {
return CATEGORY_PALETTE[index % CATEGORY_PALETTE.length];
}

For TypeScript (Chart Libraries, Inline Styles)

Section titled “For TypeScript (Chart Libraries, Inline Styles)”

When you need resolved hex values (e.g., for D3, Chart.js, or [style.color] bindings), read the computed values:

private readonly categoryPaletteTokens = [
'--mj-color-brand-500',
'--mj-color-accent-500',
'--mj-color-tertiary-500',
'--mj-color-indigo-500',
'--mj-color-violet-500',
'--mj-color-success-500',
'--mj-color-warning-500',
'--mj-color-error-500',
];
private resolveCategoryPalette(): string[] {
const root = document.documentElement;
return this.categoryPaletteTokens.map(token =>
getComputedStyle(root).getPropertyValue(token).trim()
);
}

This ensures category colors automatically adapt to the active theme.


The following files contain hardcoded hex colors that need migration. They are organized by dashboard/feature area, heaviest first.

FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/AI/components/execution-monitoring.component.ts~97Background gradients, chart cost bar segments, button hover states, status badges, tab navigation, token visualization segmentsStatus tokens for semantic states; brand/primitive tokens for chart segments; surface tokens for backgrounds
dashboards/src/AI/components/widgets/kpi-card.component.ts~10Left border indicators (primary/success/warning/danger/info), icon gradient backgrounds, hover border transitionsStatus tokens for semantic borders; brand token for primary
dashboards/src/AI/components/widgets/live-execution-widget.component.ts~2SVG progress ring colorsBrand primary for ring stroke
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Credentials/components/credentials-categories-resource.component.ts~7Category color array for chart segmentsCategory palette tokens (see Section 4)
dashboards/src/Credentials/components/credentials-types-resource.component.ts~7Type color assignmentsCategory palette tokens
dashboards/src/Credentials/components/credentials-audit-resource.component.ts~7Operation type indicators (Create/Update/Delete/Validate/Access)Status tokens for CRUD operations; category palette for non-semantic
dashboards/src/Credentials/components/credentials-overview-resource.component.ts~7Overview chart color mapCategory palette tokens
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Scheduling/components/scheduling-activity.component.ts~3Success rate conditional coloring (green/amber/red)--mj-status-success / --mj-status-warning / --mj-status-error
dashboards/src/Scheduling/components/scheduling-jobs.component.ts~3Job health indicatorsSame status token pattern
dashboards/src/Scheduling/components/scheduling-overview.component.ts~6Overview health score coloringSame status token pattern
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Testing/components/widgets/test-run-detail-panel.component.ts~20Gradient header, metric card borders, form styling, section dividersBrand gradient for header; status tokens for metric colors; surface/border tokens for layout
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Communication/communication-runs-resource.component.ts~12Stat card backgrounds/text, timeline progress dots (in-progress/completed/failed/pending)Status tokens for timeline states; surface tokens for card backgrounds
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/APIKeys/api-scopes-panel.component.ts~8Scope category color map (Entities/Agents/Admin/Actions/Queries/Reports/Communication)Category palette tokens
dashboards/src/APIKeys/api-usage-panel.component.ts~4HTTP status chart colors (2xx green, 3xx blue, 4xx amber, 5xx red)Status tokens (success/info/warning/error)
dashboards/src/APIKeys/api-key-*.component.ts~4Individual accent colorsBrand primary token
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Lists/services/list-set-operations.service.ts~8Venn diagram set colorsCategory palette tokens
dashboards/src/Lists/components/lists-my-lists-resource.component.ts~6Search box styling, header icons, item badgesSurface/text/border tokens
dashboards/src/Lists/components/lists-operations-resource.component.ts~4UI accent colorsBrand tokens
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/SystemDiagnostics/system-diagnostics.component.ts~16D3 performance chart category colors, SVG axis labels, tooltipsCategory palette tokens for series; text tokens for labels
FileHex CountWhat the Colors Are Used ForToken Replacement Strategy
dashboards/src/Home/home-dashboard.component.ts~1#1976d2 fallback for app colorRemove — use var(--mj-brand-primary)

The Actions dashboard components (categories-list-view, code-management, security-permissions) have been migrated to MJ semantic tokens. All Kendo theme variables (--kendo-color-primary, etc.) have been removed.


Several files use CSS custom variables with hardcoded hex fallbacks:

/* Example of partial migration pattern */
color: var(--some-custom-var, #6366f1);
background: var(--card-bg, #f8fafc);

These files defined their own CSS variables but used hardcoded fallbacks instead of MJ tokens. The fix for these files is:

  1. Replace the custom variable with the appropriate MJ token
  2. Remove the hex fallback — MJ tokens are always defined in _tokens.scss
/* BEFORE — custom var with hex fallback */
color: var(--some-custom-var, #6366f1);
/* AFTER — standard MJ token, no fallback needed */
color: var(--mj-brand-primary);

Known partially migrated files:

  • Communication dashboard components (using var(--mat-sys-*) Material variables)
  • Credentials category component CSS (using custom variables with hex fallbacks)

Before writing custom CSS for cards, buttons, badges, inputs, panels, or tables, check:

packages/Angular/Explorer/explorer-app/src/lib/styles/_shared-patterns.scss

This file already defines token-based styling for 60+ class name variants across these pattern families:

PatternClass NamesWhat It Provides
Cards.mj-card, .dashboard-card, .stat-card, .kpi-card, .metric-card, .action-card, .prompt-card, .agent-card, .model-card, + 30 moreBackground, border, shadow, padding, hover transitions
Card Sub-elements.mj-card-header, .card-header, .mj-card-body, .card-body, .mj-card-footer, .card-footerConsistent padding, borders, typography
Stat Elements.stat-icon, .stat-value, .stat-label, .stat-contentIcon sizing, value typography, label muting
Buttons.mj-btn, .mj-btn-primary, .mj-btn-secondary, .mj-btn-ghost, .mj-btn-danger, .mj-btn-smAll states (hover/active/focus/disabled) using tokens
Badges.mj-badge, .status-badge, .mj-badge-success, .mj-badge-warning, .mj-badge-error, .mj-badge-info, .mj-badge-neutralStatus-colored badges using token families
Inputs.mj-input, .mj-search-input, .search-input, .filter-inputBorder, focus ring, placeholder styling
Panels.mj-panel, .filter-panel, .detail-panelSurface background, header/body structure
Tables.mj-table, .data-table, .entity-tableHeader/row styling, hover, borders
Headers.dashboard-header, .mj-dashboard-headerLayout with .header-info and .header-controls regions
Empty/Loading.mj-empty-state, .empty-state, .mj-loading, .loading-stateCentered content with muted styling
Overlays.mj-loading-overlay, .loading-overlay, .mj-modal-overlaySemi-transparent overlay backgrounds
Utilities.text-muted, .text-secondary, .text-primary, .text-link, .bg-surface, .border-default, .shadow-mdQuick token-backed utility classes

How to use: Apply these class names to your component HTML. The shared patterns file is globally included, so no additional imports are needed. Components keep their semantic class names (like .kpi-card or .action-card) and get consistent token-based styling automatically.


packages/Angular/Explorer/explorer-app/src/lib/styles/_variables.scss

This file maps legacy variable names to MJ tokens for backward compatibility:

Legacy VariableMaps ToUsed By
--navy--mj-color-brand-900Legacy components
--light-blue--mj-color-accent-300Legacy components
--mj-blue--mj-color-brand-500Legacy components
--white-color--mj-color-neutral-0Legacy components
--gray-600--mj-color-neutral-100Legacy components
--gray-700--mj-color-neutral-200Legacy components
--gray-800--mj-color-neutral-400Legacy components
--gray-900--mj-color-neutral-700Legacy components
--med-gray--mj-color-neutral-200Legacy components
--shadow--mj-shadow-mdVarious
--border-radius--mj-radius-lgVarious
--transition-time--mj-transition-baseVarious

The five Kendo-specific variables (--kendo-color-primary, etc.) have been removed along with _kendo-theme-override.scss as part of the Kendo removal in Phase 2.1.

All Kendo overrides have been removed. New components should use MJ semantic tokens directly. For example:

/* BEFORE — legacy variable */
color: var(--navy);
/* WRONG — using the primitive the bridge maps to */
color: var(--mj-color-brand-900);
/* CORRECT — using the semantic token for the purpose */
color: var(--mj-brand-secondary); /* Navy is our secondary brand */

The bridge file (_variables.scss) can be removed entirely once all legacy references are migrated.


Don’t use app Color for anything beyond nav chrome

Section titled “Don’t use app Color for anything beyond nav chrome”
/* BAD — app color bleeding into content */
.dashboard-card { border-left-color: var(--app-color); }
.kpi-value { color: var(--mj-app-accent); }
/* GOOD — nav-only usage */
.nav-button:hover { background: var(--app-color); }

Don’t create per-component CSS variables that duplicate existing tokens

Section titled “Don’t create per-component CSS variables that duplicate existing tokens”
/* BAD — reinventing the wheel */
.my-component {
--my-card-bg: #f8fafc;
--my-border: #e2e8f0;
--my-text: #1e293b;
}
/* GOOD — use existing tokens */
.my-component {
background: var(--mj-bg-surface-card);
border-color: var(--mj-border-default);
color: var(--mj-text-primary);
}
/* BAD — hex fallback defeats theming */
color: var(--mj-brand-primary, #0076b6);
/* GOOD — no fallback needed, tokens are always defined */
color: var(--mj-brand-primary);
/* ALSO GOOD — fallback to another token if genuinely needed */
color: var(--mj-brand-primary-light, var(--mj-brand-primary));
/* BAD — only works in light mode */
background: #ffffff;
color: #1e293b;
/* GOOD — auto-switches with theme */
background: var(--mj-bg-surface);
color: var(--mj-text-primary);

Don’t use rgba() with hardcoded colors for transparency

Section titled “Don’t use rgba() with hardcoded colors for transparency”
/* BAD */
background: rgba(99, 102, 241, 0.1);
/* GOOD — use the subtle variant token */
background: var(--mj-brand-accent-subtle);
/* ALSO GOOD — use color-mix for custom opacity */
background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);

Before writing custom card/button/badge/panel CSS, check _shared-patterns.scss (see Section 7). If a pattern already exists, use the class name. If your use case isn’t covered, consider adding to the shared file rather than creating one-off styles.


FilePurpose
packages/Angular/Explorer/explorer-app/src/lib/styles/_tokens.scssAll MJ design tokens (primitives + semantic, light + dark)
packages/Angular/Explorer/explorer-app/src/lib/styles/_shared-patterns.scss60+ reusable token-based class patterns
packages/Angular/Explorer/explorer-app/src/lib/styles/_variables.scssLegacy variable bridge (deprecated)
_kendo-theme-override.scssDeleted — Kendo overrides removed in Phase 2.1
guides/THEMING.mdFull theming system documentation