@bernierllc/validators-a11y-contrast
v0.3.0
Published
Accessibility color contrast validation for the BernierLLC validators ecosystem - validates WCAG AA and AAA contrast requirements
Readme
@bernierllc/validators-a11y-contrast
Accessibility color contrast validation for the BernierLLC validators ecosystem - validates WCAG AA and AAA contrast requirements.
Installation
npm install @bernierllc/validators-a11y-contrastOverview
This primitive validator checks color contrast ratios against WCAG 2.1 accessibility standards. It validates both text and non-text UI elements to ensure sufficient contrast for users with visual impairments.
WCAG Standards Supported
- WCAG AA Text: 4.5:1 minimum for normal text, 3:1 for large text
- WCAG AAA Text: 7:1 minimum for normal text, 4.5:1 for large text
- Non-Text Elements: 3:1 minimum (WCAG 2.1 SC 1.4.11)
Text Size Definitions
- Normal Text: Below 18pt (24px) or below 14pt (18.67px) bold
- Large Text: 18pt (24px)+ or 14pt (18.67px)+ bold
Usage
Basic Validation
import { validateA11yContrast } from '@bernierllc/validators-a11y-contrast';
// Check normal text against WCAG AA
const problems = await validateA11yContrast({
foreground: '#777777',
background: '#ffffff',
level: 'AA',
fontSize: 'normal'
});
problems.forEach(problem => {
console.log(`${problem.severity}: ${problem.message}`);
console.log(`Suggestion: ${problem.suggestion}`);
});Quick Contrast Check
import { checkContrast } from '@bernierllc/validators-a11y-contrast';
// Get detailed contrast metrics
const result = checkContrast({
foreground: '#000000',
background: '#ffffff',
level: 'AA',
fontSize: 'normal'
});
console.log(`Contrast Ratio: ${result.contrastRatio.toFixed(2)}:1`);
console.log(`Required: ${result.required}:1`);
console.log(`Passes: ${result.passes}`);
// Output:
// Contrast Ratio: 21.00:1
// Required: 4.5:1
// Passes: trueLarge Text Validation
import { validateA11yContrast } from '@bernierllc/validators-a11y-contrast';
// Headers and large text have lower requirements
const problems = await validateA11yContrast({
foreground: '#959595',
background: '#ffffff',
level: 'AA',
fontSize: 'large'
});
// Passes with 3.5:1 ratio (minimum 3:1 for large text)
console.log(problems.length); // 0WCAG AAA Enhanced Validation
import { validateA11yContrast } from '@bernierllc/validators-a11y-contrast';
// Check against enhanced AAA standards
const problems = await validateA11yContrast({
foreground: '#595959',
background: '#ffffff',
level: 'AAA',
fontSize: 'normal'
});
// Passes with 7.1:1 ratio (minimum 7:1 for AAA normal text)
console.log(problems.length); // 0Non-Text UI Elements
import { validateA11yContrast } from '@bernierllc/validators-a11y-contrast';
// Validate button borders, icons, and graphical elements
const problems = await validateA11yContrast({
foreground: '#0066cc',
background: '#ffffff',
elementType: 'non-text'
});
// Passes with 7.9:1 ratio (minimum 3:1 for non-text)
console.log(problems.length); // 0API Reference
validateA11yContrast(input, utils?)
Validates color contrast against WCAG standards and returns validation problems.
Parameters:
input: ContrastCheckInput- Validation configurationforeground: string- Foreground color (text/UI element)background: string- Background colorlevel?: 'AA' | 'AAA'- WCAG level (default: 'AA')fontSize?: 'normal' | 'large'- Text size category (default: 'normal')elementType?: 'text' | 'non-text'- Element type (default: 'text')
utils?: SharedUtils- Optional shared utilities
Returns: Promise<Problem[]> - Array of validation problems
Color Format Support:
- Hex:
#000,#000000 - RGB:
rgb(0, 0, 0),rgba(0, 0, 0, 1) - Named:
black,white,red, etc.
checkContrast(input)
Synchronously checks contrast and returns detailed metrics.
Parameters:
input: ContrastCheckInput- Same asvalidateA11yContrast
Returns: ContrastCheckResult
passes: boolean- Whether contrast meets requirementscontrastRatio: number- Calculated contrast ratiorequired: number- Required minimum ratiolevel: 'AA' | 'AAA'- WCAG level checkedfontSize?: 'normal' | 'large'- Text size (if text)elementType: 'text' | 'non-text'- Element type
Validation Rules
Rule: a11y-contrast/insufficient-contrast-aa-normal
Severity: error
Validates normal text meets WCAG AA minimum of 4.5:1 contrast ratio.
Triggers When:
- Text contrast ratio < 4.5:1
- Element type is 'text'
- Font size is 'normal'
- Level is 'AA'
Rule: a11y-contrast/insufficient-contrast-aa-large
Severity: error
Validates large text meets WCAG AA minimum of 3:1 contrast ratio.
Triggers When:
- Text contrast ratio < 3:1
- Element type is 'text'
- Font size is 'large'
- Level is 'AA'
Rule: a11y-contrast/insufficient-contrast-aaa-normal
Severity: warning
Validates normal text meets WCAG AAA enhanced minimum of 7:1.
Triggers When:
- Text contrast ratio < 7:1
- Element type is 'text'
- Font size is 'normal'
- Level is 'AAA'
Rule: a11y-contrast/insufficient-contrast-aaa-large
Severity: warning
Validates large text meets WCAG AAA enhanced minimum of 4.5:1.
Triggers When:
- Text contrast ratio < 4.5:1
- Element type is 'text'
- Font size is 'large'
- Level is 'AAA'
Rule: a11y-contrast/insufficient-contrast-non-text
Severity: error
Validates non-text elements meet WCAG 2.1 SC 1.4.11 minimum of 3:1.
Triggers When:
- UI element contrast < 3:1
- Element type is 'non-text'
Real-World Examples
Validating Link Colors
// Standard link blue on white background
const linkProblems = await validateA11yContrast({
foreground: '#0000ee',
background: '#ffffff',
level: 'AA',
fontSize: 'normal'
});
console.log(linkProblems.length); // 0 - Passes with 8.6:1 ratioButton Border Contrast
// Validate button border stands out
const borderProblems = await validateA11yContrast({
foreground: '#0066cc', // Button border color
background: '#ffffff', // Page background
elementType: 'non-text'
});
console.log(borderProblems.length); // 0 - Passes with 7.9:1 ratioForm Input Validation
// Check placeholder text color
const placeholderProblems = await validateA11yContrast({
foreground: '#999999', // Light gray placeholder
background: '#ffffff',
level: 'AA',
fontSize: 'normal'
});
console.log(placeholderProblems.length); // 1 - Fails with 2.85:1 ratio
console.log(placeholderProblems[0].message);
// "Insufficient contrast ratio 2.85:1 (minimum 4.5:1 required for WCAG AA)"Dark Mode Validation
// Validate dark mode text
const darkModeProblems = await validateA11yContrast({
foreground: '#e0e0e0', // Light text
background: '#1a1a1a', // Dark background
level: 'AA',
fontSize: 'normal'
});
console.log(darkModeProblems.length); // 0 - Passes with 11.8:1 ratioIntegration with Other Validators
This primitive validator can be composed with other validators in the ecosystem:
import { createRuleContext } from '@bernierllc/validators-core';
import { createSharedUtils } from '@bernierllc/validators-utils';
import { a11yContrastValidator } from '@bernierllc/validators-a11y-contrast';
// Create shared utilities once
const utils = createSharedUtils();
// Create context for validation
const context = createRuleContext(
'a11y-contrast',
{ foreground: '#777', background: '#fff' },
utils
);
// Run validation
const problems = await a11yContrastValidator.validate(
{ foreground: '#777', background: '#fff', level: 'AA', fontSize: 'normal' },
context
);Dependencies
@bernierllc/validators-core- Core validation framework@bernierllc/validators-utils- Shared utilities including color parsing and contrast calculation
Integration Status
Logger Integration
Not applicable - This is a pure validation utility with no side effects or logging requirements. As a primitive validator focused solely on color contrast calculations, it follows the validators architecture principle where logging is handled by higher-level domain validators or the validation runner.
Docs-Suite Compatibility
Ready - Package includes complete markdown documentation that can be integrated into docs-suite. All validation rules are documented with examples and usage patterns.
NeverHub Integration
Not applicable - This is a primitive validator that operates synchronously on input data. Following the validators architecture, primitive validators do not integrate with NeverHub. Service discovery and event publishing are responsibilities of domain validators and validator orchestrators that consume this primitive.
Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests once
npm run test:runQuality Standards
- Test Coverage: 90%+ (branches, functions, lines, statements)
- TypeScript: Strict mode enabled
- Linting: Zero errors or warnings
- Real Data: Tests use actual color values
Contributing
This package follows BernierLLC standards:
- Single responsibility (contrast validation only)
- Pure functions
- Comprehensive test coverage
- Real-world testing data
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
See Also
- @bernierllc/validators-core - Core validation framework
- @bernierllc/validators-utils - Shared validation utilities
- @bernierllc/validators-html-syntax - HTML syntax validation
- WCAG 2.1 Guidelines - Official WCAG documentation
