# How Accessibility Themes Are Contrast-Checked in Ontology Playground: A WCAG 2.1 Implementation Guide

> Learn how Ontology Playground automatically contrast-checks accessibility themes against WCAG 2.1 standards. Discover the automated testing process for reliable accessibility.

- Repository: [Microsoft/Ontology-Playground](https://github.com/microsoft/Ontology-Playground)
- Tags: how-to-guide
- Published: 2026-07-23

---

**Microsoft Ontology Playground enforces WCAG 2.1 Level AA compliance by extracting CSS custom properties from [`src/styles/app.css`](https://github.com/microsoft/Ontology-Playground/blob/main/src/styles/app.css), computing precise contrast ratios using WCAG-standard algorithms, and running automated tests that assert all theme token pairs meet minimum thresholds of 4.5:1 for text and 3:1 for non-text graphics.**

The Ontology Playground repository by Microsoft implements a rigorous accessibility verification pipeline that ensures every visual theme meets strict color contrast requirements. By combining CSS token extraction with automated WCAG 2.1 calculations, the codebase prevents low-contrast themes from reaching production through comprehensive test coverage.

## Extracting Theme Tokens from Source Stylesheets

The contrast verification process begins by reading actual CSS custom properties directly from the source stylesheet. In [`src/a11y/themeTokens.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/a11y/themeTokens.ts), the `getThemeTokens()` function parses [`src/styles/app.css`](https://github.com/microsoft/Ontology-Playground/blob/main/src/styles/app.css) to build a mapping of token names to computed values for each supported theme.

The function handles theme cascading by merging selectors in specificity order, starting with `:root` and progressing through theme-specific classes like `.light-theme`. This approach ensures the test suite evaluates the exact same CSS values that render in the browser, not hardcoded copies that could drift out of sync.

```typescript
// src/a11y/themeTokens.ts
export function getThemeTokens(theme: ThemeId): Record<string, string> {
  const css = readCss();                     // reads src/styles/app.css once
  const merged: Record<string, string> = {};
  for (const selector of THEME_SELECTORS[theme]) {
    Object.assign(merged, extractVars(css, selector));
  }
  return merged;
}

```

## Calculating WCAG 2.1 Contrast Ratios

The mathematical foundation lives in [`src/a11y/contrast.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/a11y/contrast.ts), which implements the exact WCAG 2.1 specifications for color contrast. The module exports four critical functions: `parseColor()` for hex/rgba parsing, `composite()` for alpha blending, `relativeLuminance()` for linear luminance calculation, and `contrastRatio()` for the final comparison.

When calculating ratios, the system first validates that background colors are opaque, then composites any translucent foregrounds over their backgrounds before computing luminance values. The algorithm follows the standard WCAG formula: `(L1 + 0.05) / (L2 + 0.05)`, where L1 and L2 represent the relative luminance of the lighter and darker colors respectively.

```typescript
// src/a11y/contrast.ts
export function contrastRatio(foreground: string, background: string): number {
  const bg = parseColor(background);
  if (bg.a < 1) {
    throw new Error(`Background color must be opaque …`);
  }
  const fg = parseColor(foreground);
  const fgOpaque: RGB = fg.a < 1 ? composite(fg, bg) : fg;
  const l1 = relativeLuminance(fgOpaque);
  const l2 = relativeLuminance(bg);
  return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
}

```

## Automated Contrast Enforcement via Testing

The enforcement mechanism resides in [`src/a11y/themeContrast.test.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/a11y/themeContrast.test.ts), which defines the contract between design tokens and accessibility standards. The test suite iterates over all four themes—`dark`, `light`, `aurora`, and `crimson`—and evaluates every required foreground and background token pair against WCAG thresholds.

Normal text must achieve a **4.5:1 contrast ratio**, while non-text graphics (UI components, icons) require **3:1**. The test framework dynamically generates assertions for each combination, causing immediate build failures if any theme modification introduces insufficient contrast.

```typescript
// src/a11y/themeContrast.test.ts
describe('WCAG 2.1 AA theme contrast (SC 1.4.3 / 1.4.11)', () => {
  for (const theme of THEMES) {
    const tokens = getThemeTokens(theme);
    describe(theme, () => {
      for (const pair of PAIRS) {
        const minimum = pair.kind === 'text' ? AA_NORMAL_TEXT : AA_NON_TEXT;
        it(`${pair.name} meets ${minimum}:1`, () => {
          const fg = tokens[pair.fg];
          const bg = tokens[pair.bg];
          const ratio = contrastRatio(fg, bg);
          expect(ratio).toBeGreaterThanOrEqual(minimum);
        });
      }
    });
  }
});

```

## Handling Translucent Colors and Special Components

Beyond basic text and background pairs, the validation pipeline addresses complex UI scenarios involving transparency and special color treatments.

**Stat-card tiles** undergo verification that their composited backgrounds (translucent tints layered over sidebar surfaces) maintain the 3:1 non-text threshold. The **amber foreground** token (`--ms-yellow-fg`) receives explicit testing to ensure 4.5:1 contrast across all surfaces, including warning tile backgrounds. For **progress bars**, both gradient stops (`--progress-from` and `--progress-to`) are checked against the track color (`--bg-tertiary`) to guarantee visibility regardless of fill level.

## Practical Implementation Example

Developers can programmatically verify custom token combinations using the exported utilities:

```typescript
import { getThemeTokens } from './a11y/themeTokens';
import { contrastRatio, AA_NORMAL_TEXT } from './a11y/contrast';

// Example: Check primary text on the app background for the "light" theme
const tokens = getThemeTokens('light');
const fg = tokens['--text-primary'];   // e.g. "#212121"
const bg = tokens['--bg-primary'];     // e.g. "#ffffff"

const ratio = contrastRatio(fg, bg);
console.log(`Contrast ratio: ${ratio.toFixed(2)}:1`);
if (ratio >= AA_NORMAL_TEXT) {
  console.log('✅ Meets WCAG AA for normal text');
} else {
  console.warn('⚠️ Does NOT meet the required contrast');
}

```

## Summary

- **Source-driven validation**: The `getThemeTokens()` function extracts live CSS custom properties from [`src/styles/app.css`](https://github.com/microsoft/Ontology-Playground/blob/main/src/styles/app.css), ensuring tests always evaluate current stylesheet values.
- **WCAG 2.1 Level AA compliance**: The [`contrast.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/contrast.ts) module implements standard algorithms for luminance calculation and alpha compositing, enforcing 4.5:1 ratios for text and 3:1 for non-text elements.
- **Comprehensive theme coverage**: Automated tests in [`themeContrast.test.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/themeContrast.test.ts) validate four distinct themes (`dark`, `light`, `aurora`, `crimson`) across all token pairs.
- **Special case handling**: The suite accounts for translucent layers in stat-cards, high-visibility requirements for amber foregrounds, and multi-stop gradients in progress bars.

## Frequently Asked Questions

### What WCAG conformance level does Ontology Playground target?

The codebase targets **WCAG 2.1 Level AA** according to Success Criteria 1.4.3 (Contrast Minimum) and 1.4.11 (Non-text Contrast). This requires normal text to achieve a minimum contrast ratio of 4.5:1 against its background, while large text and non-text user interface components must meet a 3:1 ratio.

### How does the contrast checker handle semi-transparent colors?

The `contrastRatio()` function in [`src/a11y/contrast.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/a11y/contrast.ts) rejects translucent backgrounds and composites translucent foregrounds over their opaque backgrounds before calculation. This ensures the final ratio reflects the actual rendered appearance rather than the raw alpha values, preventing false positives on partially transparent UI elements.

### Which themes are validated by the automated test suite?

The test suite validates four distinct themes: `dark`, `light`, `aurora`, and `crimson`. Each theme undergoes identical token extraction and contrast validation processes, ensuring consistent accessibility standards regardless of the user's selected color preference.

### What happens if a theme fails the contrast check?

If [`themeContrast.test.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/themeContrast.test.ts) detects any token pair with a contrast ratio below the WCAG threshold, the test assertion fails and prevents the build from passing. This integration into the continuous integration pipeline ensures that insufficient contrast ratios block deployment, maintaining accessibility compliance by default.