{
"path": "/articles/2025-wcag-color-contrast-validation-in-craft",
"site": "at://did:plc:kq2tuvvnlen4jjcqiw4oprjm/site.standard.publication/3mhyhqc3kcaw7",
"tags": [
"Craft CMS",
"Accessibility"
],
"$type": "site.standard.document",
"title": "WCAG Color contrast validation in Craft",
"content": {
"html": "<div><h2></h2><p>One of my colleagues asked if there wasn't some way in which we could validate the color against the WCAG level we're trying to hit for the project. A couple of quick searches brought me to <a href=\"https://www.w3.org/WAI/GL/wiki/Relative_luminance\">this page</a> which covers how to calculate relative luminance for a color and <a href=\"https://www.w3.org/WAI/GL/wiki/Contrast_ratio\">this one</a> which covers how to compare 2 colors to get the contrast ratio.</p>\n</div><div><h2>Claude Code enters the.... terminal?</h2><p>I had been looking forward to giving Claude Code a spin to build an actual feature, seeing how well I can get it to \"use\" Craft.</p>\n<p>I enter the links about the relative luminance & contrast ratio calculation, supplemented with <a href=\"https://context7.com/about\">Context7</a>, where I had it read the <a href=\"https://context7.com/craftcms/docs\">documentation for Craft CMS</a>.</p>\n<p>After that I told it what I wanted to create - a validation rule for my field handle (colorFieldWithValidation) that throws a validation error when the selected color doesn't have enough contrast with the text color. Text color should be configurable per field.</p>\n</div><div><h2>Planning mode</h2><p>Claude Code has a \"planning mode\" where it first creates an outline or a todo list of all the steps it determines need to be taken. That first stab at things included a new field type, which had color validation built in and had settings for text color per field.</p>\n<p>That would have worked but was a bit too elaborate for what I had in mind. I then passed it <a href=\"https://nystudio107.com/blog/extending-craft-cms-with-validation-rules-and-behaviors\">this article</a> about validation rules from nystudio107 and told it to drop the new field type in favor of a validation rule.</p>\n</div><div></div><div><h2></h2><p>After 4 or 5 more prompts nudging it (I'll keep calling Claude Code \"it\" for now) in the right direction and making some slight tweaks myself, the results were in line with what I was looking for, with a straightforward way to configure the validator for one or multiple fields.</p>\n<p>We can determine the field we want to add the validator to by using its handle, the color of the text that will be displayed on the color selected through the field and the WCAG level we want to reach.</p>\n</div><div><h2></h2><pre><code>public static function define(): array\n {\n return [\n // Test field for validation testing - test against white text\n [\n 'field:colorFieldWithValidator',\n ContrastValidator::class,\n 'textColor' => '#000',\n 'wcagLevel' => 'AAA',\n 'message' => Craft::t('site', 'Color does not meet WCAG AAA contrast requirements (7.0:1) against white text. Current ratio: {ratio}:1'),\n ],\n ];\n }</code></pre></div><div><h2>Wrapping things up</h2><p>I committed everything to a little private plugin, which you can find on <a href=\"https://github.com/studioespresso/craft-contrast-rules\">on Github</a>. There are a bunch of additions or improvements that can be made (configuring the rules through the CP, creating a new field type where the user can select both text and background color, etc.)</p>\n<p>Like I said at the top, we try to avoid letting clients choose their own colors if at all possible so for now I'm going to keep the plugin as is, bare bones and focused on just validating the existing color field.</p>\n</div><div><h2>To Claude Code or not?</h2><p>AI has definitely taken its place in the software development toolchain and it's not going anywhere. While I usually remain skeptical about most things AI related, there's no denying that it has the potential to change our jobs and how we do them (and in some cases that change is already here).</p>\n<p>In this case, Claude Code did a decent job creating something usable. I'm quite sure it wouldn't have gone so smoothly if it weren't for the detailed hints I provided (the WCAG calculation and the article on validation rules) and the years of experience I have personally writing code for Craft CMS.</p>\n</div><div><h2></h2><p>If you'd like to share your thoughts on this plugin or on using AI for development in Craft CMS, feel free to reach out to me in Craft's Discord, through <a href=\"mailto:jan@studioespresso.co\">email</a> or on <a href=\"https://bsky.app/profile/janhenckens.bsky.social\">BlueSky</a></p>\n</div>",
"$type": "org.wordpress.html"
},
"updatedAt": "2025-07-05T15:12:02+02:00",
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreidxwtqo7teghkgcevlpedqxzqsznwd3dygm5dnjonat2ntzur444m"
},
"mimeType": "image/jpeg",
"size": 1197016
},
"description": "While talking with 2 colleagues last week, we were discussing a project where the client asked for the option to be able to \"theme\" certain pages themselves, to match the branding of some of their own future projects. Letting a client choose their own background color probably brings out a bunch of red flags for you - as it did for me.",
"publishedAt": "2025-07-02T20:29:00+02:00",
"textContent": "One of my colleagues asked if there wasn't some way in which we could validate the color against the WCAG level we're trying to hit for the project. A couple of quick searches brought me to this page which covers how to calculate relative luminance for a color and this one which covers how to compare 2 colors to get the contrast ratio.\nClaude Code enters the.... terminal?I had been looking forward to giving Claude Code a spin to build an actual feature, seeing how well I can get it to \"use\" Craft.\nI enter the links about the relative luminance & contrast ratio calculation, supplemented with Context7, where I had it read the documentation for Craft CMS.\nAfter that I told it what I wanted to create - a validation rule for my field handle (colorFieldWithValidation) that throws a validation error when the selected color doesn't have enough contrast with the text color. Text color should be configurable per field.\nPlanning modeClaude Code has a \"planning mode\" where it first creates an outline or a todo list of all the steps it determines need to be taken. That first stab at things included a new field type, which had color validation built in and had settings for text color per field.\nThat would have worked but was a bit too elaborate for what I had in mind. I then passed it this article about validation rules from nystudio107 and told it to drop the new field type in favor of a validation rule.\nAfter 4 or 5 more prompts nudging it (I'll keep calling Claude Code \"it\" for now) in the right direction and making some slight tweaks myself, the results were in line with what I was looking for, with a straightforward way to configure the validator for one or multiple fields.\nWe can determine the field we want to add the validator to by using its handle, the color of the text that will be displayed on the color selected through the field and the WCAG level we want to reach.\npublic static function define(): array\n {\n return [\n // Test field for validation testing - test against white text\n [\n 'field:colorFieldWithValidator',\n ContrastValidator::class,\n 'textColor' => '#000',\n 'wcagLevel' => 'AAA',\n 'message' => Craft::t('site', 'Color does not meet WCAG AAA contrast requirements (7.0:1) against white text. Current ratio: {ratio}:1'),\n ],\n ];\n }Wrapping things upI committed everything to a little private plugin, which you can find on on Github. There are a bunch of additions or improvements that can be made (configuring the rules through the CP, creating a new field type where the user can select both text and background color, etc.)\nLike I said at the top, we try to avoid letting clients choose their own colors if at all possible so for now I'm going to keep the plugin as is, bare bones and focused on just validating the existing color field.\nTo Claude Code or not?AI has definitely taken its place in the software development toolchain and it's not going anywhere. While I usually remain skeptical about most things AI related, there's no denying that it has the potential to change our jobs and how we do them (and in some cases that change is already here).\nIn this case, Claude Code did a decent job creating something usable. I'm quite sure it wouldn't have gone so smoothly if it weren't for the detailed hints I provided (the WCAG calculation and the article on validation rules) and the years of experience I have personally writing code for Craft CMS.\nIf you'd like to share your thoughts on this plugin or on using AI for development in Craft CMS, feel free to reach out to me in Craft's Discord, through email or on BlueSky\n"
}