# How the Contrast-Ratio Rule Ensures WCAG Accessibility Compliance in design.md

> Ensure WCAG accessibility compliance with the contrast-ratio rule. This rule enforces a minimum 4.5:1 contrast ratio for text and backgrounds, flagging violations to improve your designs.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-07-03

---

**The contrast-ratio rule automatically validates that every component meets the WCAG 2.1 AA standard by requiring a minimum 4.5:1 contrast ratio between text and background colors, flagging violations as linter warnings.**

The google-labs-code/design.md repository provides a CLI linter that enforces accessibility standards across design system components without manual review. The contrast-ratio rule specifically targets WCAG compliance by analyzing `backgroundColor` and `textColor` properties defined in DESIGN.md files, ensuring text remains readable for users with visual impairments.

## How the Contrast-Ratio Rule Works

The rule implements a three-step pipeline that runs on every component definition. According to the source code in [`packages/cli/src/linter/linter/rules/contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/linter/rules/contrast-ratio.ts), the process resolves color tokens, calculates luminance-based contrast, and compares results against the WCAG AA threshold.

### Step 1: Resolve Token Values

For each component, the rule extracts `backgroundColor` and `textColor` properties, dereferences any token references (such as `{colors.primary}`), and converts them into concrete `ResolvedColor` objects. The `resolveToColor` helper ensures only valid color objects proceed to calculation.

This resolution happens in [`contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/contrast-ratio.ts) lines 47-52, where the linter handles both direct hex values and token references defined in the DESIGN.md file.

### Step 2: Compute WCAG Contrast

The linter calls the `contrastRatio` utility function defined in [`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts) (lines 400-406). This pure function applies the official WCAG luminance formula:

```typescript
(L1 + 0.05) / (L2 + 0.05)

```

The calculation uses relative luminance values stored on each `ResolvedColor` object, comparing the lighter color (L1) against the darker color (L2) to produce a ratio that indicates how distinguishable the colors are.

### Step 3: Compare Against AA Threshold

The rule enforces the constant `WCAG_AA_MINIMUM = 4.5`, which mirrors the WCAG 2.1 AA requirement for normal-sized text. In [`contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/contrast-ratio.ts) lines 36-42, the linter checks:

```typescript
if (ratio < WCAG_AA_MINIMUM) {
  // Create RuleFinding with offending colors and actual ratio
}

```

When the computed ratio falls below 4.5, the rule emits a warning `RuleFinding` that includes the specific color values, the calculated contrast ratio, and a clear failure message.

## Implementation Details

The contrast-ratio rule relies on two primary source files within the repository:

- **[`packages/cli/src/linter/linter/rules/contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/linter/rules/contrast-ratio.ts)**: Implements the rule logic that extracts color properties, handles token resolution, and creates findings when thresholds are not met.
- **[`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts)**: Provides the `contrastRatio` utility function that performs the luminance calculations according to WCAG specifications.

The rule is documented in the README.md under "Linting Rules," confirming its severity level and description for end-users.

## Practical Examples

### Command Line Usage

Run the linter against any DESIGN.md file to check for contrast violations:

```bash
npx @google/design.md lint my-design.md --format markdown

```

When a component violates the standard, the output displays the specific violation:

```

components.Button:
  textColor (#ffffff) on backgroundColor (#e0e0e0) has contrast ratio 2.87:1,
  below WCAG AA minimum of 4.5:1.

```

### Programmatic API Integration

You can invoke the contrast-ratio rule directly through the TypeScript API:

```typescript
import { lint } from '@google/design.md/linter';

const designMarkdown = `
components:
  Card:
    backgroundColor: "#f3f3f3"
    textColor: "#777777"
`;

const report = lint(designMarkdown);

for (const finding of report.findings) {
  if (finding.message.includes('contrast ratio')) {
    console.log(`⚠️ ${finding.path}: ${finding.message}`);
  }
}

```

This approach returns the same warning data structure as the CLI, allowing you to integrate contrast checks into CI/CD pipelines or custom build tools.

### DESIGN.md Configuration That Triggers Warnings

The following YAML structure demonstrates a common token resolution scenario that fails compliance:

```yaml
components:
  Alert:
    backgroundColor: "{colors.primary}"
    textColor: "#ffffff"
colors:
  primary: "#c0c0c0"

```

When linted, the rule resolves `{colors.primary}` to `#c0c0c0`, computes a contrast ratio of approximately **1.79:1** against the white text, and reports a warning because this falls well below the 4.5:1 minimum.

## Summary

- The contrast-ratio rule enforces **WCAG 2.1 AA compliance** by requiring a minimum 4.5:1 contrast ratio for all component text and background combinations.
- The implementation uses a **three-step pipeline**: token resolution in [`contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/contrast-ratio.ts), luminance calculation in [`handler.ts`](https://github.com/google-labs-code/design.md/blob/main/handler.ts), and threshold comparison against the `WCAG_AA_MINIMUM` constant.
- Violations generate **automated warnings** that include specific color values and calculated ratios, enabling rapid identification of accessibility issues.
- The rule supports both **CLI execution** and **programmatic API usage**, making it suitable for integration into design system workflows and continuous integration pipelines.

## Frequently Asked Questions

### What WCAG standard does the contrast-ratio rule enforce?

The rule enforces the **WCAG 2.1 Level AA** standard, which requires a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text (18pt or 14pt bold). The implementation uses the constant `WCAG_AA_MINIMUM = 4.5` defined in the source code to validate compliance automatically.

### How does the rule handle design tokens and color references?

The rule uses the `resolveToColor` helper function to dereference token values like `{colors.primary}` before performing calculations. This ensures that the contrast evaluation works against the actual resolved color values rather than token names, providing accurate accessibility checking even when colors are defined centrally in the DESIGN.md file.

### What happens when a component fails the contrast check?

When the calculated ratio falls below 4.5, the linter creates a `RuleFinding` object containing the specific component path, the offending background and text colors, the actual calculated ratio, and a descriptive message. This finding appears in the linter report as a warning and can be output in various formats including Markdown and JSON.

### Can I use the contrast-ratio rule outside of the CLI?

Yes. The rule is fully accessible through the programmatic API by importing the `lint` function from `@google/design.md/linter`. When you pass a DESIGN.md string to this function, it processes all rules including contrast-ratio, returning a report object containing any findings. This allows integration into custom testing frameworks, pre-commit hooks, or build processes.