Skip to content

Commit e09e40b

Browse files
Merge pull request #53 from mapbox/add-check-color-contrast-tool
[tools] Add check_color_contrast_tool for WCAG accessibility compliance
2 parents 3e1e166 + 91fc7ad commit e09e40b

File tree

7 files changed

+849
-0
lines changed

7 files changed

+849
-0
lines changed

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,66 @@ An array of four numbers representing the bounding box: `[minX, minY, maxX, maxY
625625
- "Calculate the bounding box of this GeoJSON file" (then upload a .geojson file)
626626
- "What's the bounding box for the coordinates in the uploaded parks.geojson file?"
627627

628+
#### Color Contrast Checker tool
629+
630+
Checks color contrast ratios between foreground and background colors for WCAG 2.1 accessibility compliance.
631+
632+
**Parameters:**
633+
634+
- `foregroundColor` (string, required): Foreground color (text color) in any CSS format (hex, rgb, rgba, named colors)
635+
- `backgroundColor` (string, required): Background color in any CSS format (hex, rgb, rgba, named colors)
636+
- `level` (string, optional): WCAG conformance level to check against ("AA" or "AAA", default: "AA")
637+
- `fontSize` (string, optional): Font size category ("normal" or "large", default: "normal")
638+
- Normal: < 18pt or < 14pt bold
639+
- Large: ≥ 18pt or ≥ 14pt bold
640+
641+
**Color format support:**
642+
643+
- Hex colors: `#RGB`, `#RRGGBB`, `#RRGGBBAA`
644+
- RGB/RGBA: `rgb(r, g, b)`, `rgba(r, g, b, a)`
645+
- Named colors: `black`, `white`, `red`, `blue`, `gray`, etc.
646+
647+
**WCAG 2.1 requirements:**
648+
649+
- WCAG AA: 4.5:1 for normal text, 3:1 for large text
650+
- WCAG AAA: 7:1 for normal text, 4.5:1 for large text
651+
652+
**Returns:**
653+
654+
A JSON object with:
655+
656+
- `contrastRatio`: Calculated contrast ratio (e.g., 21 for black on white)
657+
- `passes`: Whether the combination meets the specified WCAG level
658+
- `level`: WCAG level checked ("AA" or "AAA")
659+
- `fontSize`: Font size category ("normal" or "large")
660+
- `minimumRequired`: Minimum contrast ratio required for the level and font size
661+
- `wcagRequirements`: Complete WCAG contrast requirements for all levels
662+
- `recommendations`: Array of suggestions (only included when contrast fails)
663+
664+
**Example:**
665+
666+
```json
667+
{
668+
"contrastRatio": 21,
669+
"passes": true,
670+
"level": "AA",
671+
"fontSize": "normal",
672+
"minimumRequired": 4.5,
673+
"wcagRequirements": {
674+
"AA": { "normal": 4.5, "large": 3.0 },
675+
"AAA": { "normal": 7.0, "large": 4.5 }
676+
}
677+
}
678+
```
679+
680+
**Example prompts:**
681+
682+
- "Check if black text on white background is WCAG AA compliant"
683+
- "What's the contrast ratio between #4264fb and white?"
684+
- "Does gray text (#767676) on white meet AAA standards for large text?"
685+
- "Check color contrast for rgb(51, 51, 51) on rgb(245, 245, 245)"
686+
- "Is this color combination accessible: foreground 'navy' on background 'lightblue'?"
687+
628688
#### compare_styles_tool
629689

630690
Compares two Mapbox styles and reports structural differences, including changes to layers, sources, and properties. This offline comparison tool performs deep object comparison without requiring API access.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Mapbox, Inc.
2+
// Licensed under the MIT License.
3+
4+
import { z } from 'zod';
5+
6+
export const CheckColorContrastInputSchema = z.object({
7+
foregroundColor: z
8+
.string()
9+
.min(1)
10+
.describe(
11+
'Foreground color (text color) in any CSS format (hex, rgb, rgba, named colors)'
12+
),
13+
backgroundColor: z
14+
.string()
15+
.min(1)
16+
.describe(
17+
'Background color in any CSS format (hex, rgb, rgba, named colors)'
18+
),
19+
level: z
20+
.enum(['AA', 'AAA'])
21+
.optional()
22+
.describe('WCAG conformance level to check against (default: AA)'),
23+
fontSize: z
24+
.enum(['normal', 'large'])
25+
.optional()
26+
.describe(
27+
'Font size category: normal (<18pt or <14pt bold) or large (≥18pt or ≥14pt bold)'
28+
)
29+
});
30+
31+
export type CheckColorContrastInput = z.infer<
32+
typeof CheckColorContrastInputSchema
33+
>;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Mapbox, Inc.
2+
// Licensed under the MIT License.
3+
4+
import { z } from 'zod';
5+
6+
const WcagLevelRequirementsSchema = z.object({
7+
AA: z.object({
8+
normal: z.number().describe('Minimum contrast ratio for normal text (AA)'),
9+
large: z.number().describe('Minimum contrast ratio for large text (AA)')
10+
}),
11+
AAA: z.object({
12+
normal: z.number().describe('Minimum contrast ratio for normal text (AAA)'),
13+
large: z.number().describe('Minimum contrast ratio for large text (AAA)')
14+
})
15+
});
16+
17+
export const CheckColorContrastOutputSchema = z.object({
18+
contrastRatio: z
19+
.number()
20+
.describe('Calculated contrast ratio between foreground and background'),
21+
passes: z
22+
.boolean()
23+
.describe('Whether the contrast ratio meets the specified WCAG level'),
24+
level: z.string().describe('WCAG level checked (AA or AAA)'),
25+
fontSize: z.string().describe('Font size category (normal or large)'),
26+
minimumRequired: z
27+
.number()
28+
.describe(
29+
'Minimum contrast ratio required for the specified level and font size'
30+
),
31+
wcagRequirements: WcagLevelRequirementsSchema.describe(
32+
'Complete WCAG contrast requirements for all levels'
33+
),
34+
recommendations: z
35+
.array(z.string())
36+
.optional()
37+
.describe('Optional recommendations for improvement')
38+
});
39+
40+
export type CheckColorContrastOutput = z.infer<
41+
typeof CheckColorContrastOutputSchema
42+
>;

0 commit comments

Comments
 (0)