Skip to content

Custom Themes Contrast

DodaTech 3 min read

title: "Custom Themes and Contrast" weight: 21 description: "Learn how to ensure color contrast in custom themes and user-generated content: theme color customization, contrast-safe color palettes, user-controlled theming, and automated contrast enforcement." date: 2026-06-28 lastmod: 2026-06-28 tags: [accessibility, color-contrast]


Custom themes present unique contrast challenges because users can change colors arbitrarily, requiring theme systems to enforce contrast-safe color combinations, provide accessible defaults, and validate user-selected colors against WCAG thresholds.

## What You'll Learn

You will design accessible theming systems, validate user-selected colors, provide contrast-safe alternatives, and handle dark mode and high contrast mode theming.

## Why It Matters

If your application allows users to customize colors (themes, profiles, dashboards), you must ensure every possible color combination remains accessible. A user who accidentally picks a low-contrast theme may not be able to use the application.

## Real-World Use

A dashboard app lets users customize accent colors. A user picks light yellow (#FFF3CD) as their accent on a white background. The accent text becomes illegible. The app should have prevented this by validating the color against WCAG thresholds or providing contrast-safe alternatives.

## Theme Contrast Workflow

```mermaid
flowchart TD
  A[User Selects Color] --> B[Validate Contrast]
  B --> C{Passes AA?}
  C -->|Yes| D[Apply Theme]
  C -->|No| E[Suggest Alternative]
  E --> F[User Confirms]

Building Accessible Themes

Provide predefined themes that are fully tested, or validate custom colors against contrast requirements.

<!-- Theme selector with accessible presets -->
<div class="theme-picker">
  <label>Choose a theme:</label>
  <select id="theme-select">
    <option value="light">Light (default, accessible)</option>
    <option value="dark">Dark (accessible)</option>
    <option value="high-contrast">High Contrast (AAA)</option>
  </select>
</div>
/* Theme variables with accessible defaults */
:root {
  --bg-primary: #ffffff;
  --text-primary: #1a1a1a;
  --accent-color: #0056b3;
  --accent-text: #ffffff;
  /* All contrast pairs verified: pass AA minimum */
}

[data-theme="dark"] {
  --bg-primary: #1a1a1a;
  --text-primary: #e0e0e0;
  --accent-color: #66b3ff;
  --accent-text: #1a1a1a;
  /* Dark mode contrast verified */
}

[data-theme="high-contrast"] {
  --bg-primary: #000000;
  --text-primary: #ffffff;
  --accent-color: #ffff00;
  --accent-text: #000000;
  /* High contrast: exceeds AAA */
}
// Custom theme color validation
function validateThemeColor(color, bgColor, label) {
  const ratio = getContrastRatio(color, bgColor);

  if (ratio >= 4.5) {
    return { valid: true, ratio, level: 'AA' };
  }

  // Suggest a darker/lighter alternative
  const suggested = adjustColorForContrast(color, bgColor, 4.5);
  return {
    valid: false,
    ratio,
    suggested,
    message: `${label} has ${ratio.toFixed(1)}:1 contrast. Try ${suggested}`
  };
}

// Apply validated theme
function applyTheme(colors) {
  const primaryText = colors.text || '#1a1a1a';
  const background = colors.background || '#ffffff';

  const textCheck = validateThemeColor(primaryText, background, 'Text');

  if (!textCheck.valid) {
    showWarning(textCheck.message);
    document.documentElement.style.setProperty('--text-primary', textCheck.suggested);
  } else {
    document.documentElement.style.setProperty('--text-primary', primaryText);
  }

  document.documentElement.style.setProperty('--bg-primary', background);
}

Common Mistakes

  • Allowing user-selected colors without contrast validation
  • Only testing theme colors against white backgrounds
  • Not providing accessible theme presets
  • Forgetting to validate hover, focus, and active states in themes
  • Ignoring dark mode contrast requirements
  • Not testing themes with color blindness simulation
  • Assuming all users understand contrast requirements

Practice and Challenge

Practice 1: Check if your site's theme system enforces contrast. Practice 2: Create three accessible theme presets that pass WCAG AA. Practice 3: Build a color validator for a custom theme picker. Practice 4: Test dark mode contrast on your site. Practice 5: Verify a high contrast theme option passes AAA.

Challenge: Build a complete accessible theming system that: provides at least 4 predefined themes (light, dark, high contrast, color blind safe), allows custom color selection with real-time contrast validation, suggests alternatives when colors fail, and persists theme selections. Test every theme combination for WCAG AA compliance.

FAQ

How do I ensure themes are accessible?

Predefine tested themes. For custom colors, validate contrast ratios and reject or suggest alternatives for failing combinations.

Should I restrict user color choices?

You can allow any color but must validate contrast before applying. Offer suggestions for failing combinations.

How many themes should I provide?

At minimum: light and dark. Add high contrast and color blind safe options for better accessibility.

Does dark mode automatically solve contrast?

No. Dark mode can have its own contrast issues. Test all color pairs in dark mode separately.

How do I handle user-generated content?

Validate content colors against the theme. For embeds and images, ensure surrounding text has sufficient contrast.

What if a user insists on a failing color?

Allow it with a warning. Some users may have specific needs or preferences that override standard guidelines.

Mini Project

Create a theme accessibility checker that scans a page's CSS custom properties, extracts all color pairs (foreground/background), validates each against WCAG AA, and generates a report showing which color pairs pass and fail. Include a suggestion engine that proposes alternative colors for failing pairs.

What's Next

Dark Mode Contrast covers dark mode-specific contrast considerations.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro