{"version":"https://jsonfeed.org/version/1","title":"Aaron Gustafson: Content tagged accessibility","description":"The latest 20 posts and links tagged accessibility.","home_page_url":"https://www.aaron-gustafson.com","feed_url":"https://www.aaron-gustafson.com/feeds/accessibility.json","author":{"name":"Aaron Gustafson","url":"https://www.aaron-gustafson.com"},"icon":"https://www.aaron-gustafson.com/i/og-logo.png","favicon":"https://www.aaron-gustafson.com/favicon.png","expired":false,"items":[{"id":"https://www.aaron-gustafson.com/notebook/links/people-are-not-static-we-are-dynamic-in-order-to-meet-our-needs-at-any-point-in-our-lives-or-day-the-uis-we-create-must-be-able-to-adapt-to-us-not-the-other-way-around-/","title":"🔗 Different contexts, different tools, same person","summary":"People are not static, we are dynamic. In order to meet our needs at any point in our lives or day, the UIs we create must be able to adapt to us — not the other way around.","content_html":"<p>People are not static, we are dynamic. In order to meet our needs at any point in our lives or day, the UIs we create must be able to adapt to us — not the other way around.</p>\n<blockquote>\n<p>I know someone that uses her screen reader on her mobile phone, but when she’s on her desktop computer, she uses a mangifier.</p>\n<p>Different contexts, different tools, same person.</p>\n<p>I know someone that uses voice controls on his computer. He uses direct commands like “Click Contact Us” when he’s near the start of his day, and commands like “Click link, twelve” when he’s near the end of his day with lower energy and less clear speech and a dry mouth.</p>\n<p>Different energy/capacity, same tools, same person.</p>\n<p>I know someone that uses a switch on his computer. He also uses the onscreen keyboard on his computer. The one that he chooses reflects the task he’s trying to accomplish and how he can minimize switching between the tools.</p>\n<p>Different task, same context, same tools, same person.</p>\n<p>Disability is not black and white… it’s every shade of every colour.</p>\n</blockquote>\n","social_text":"People are not static, we are dynamic. In order to meet our needs at any point in our lives or day, the UIs we create must be able to adapt to us — not the other way around.","url":"https://www.aaron-gustafson.com/notebook/links/people-are-not-static-we-are-dynamic-in-order-to-meet-our-needs-at-any-point-in-our-lives-or-day-the-uis-we-create-must-be-able-to-adapt-to-us-not-the-other-way-around-/","external_url":"https://www.linkedin.com/posts/derekfeatherstone_accessibility-disability-activity-7434648295420870656-mH3o","tags":["accessibility","progressive enhancement","inclusive design"],"image":"https://static.licdn.com/aero-v1/sc/h/c45fy346jw096z9pbphyyhdz7","date_published":"2026-03-05T18:38:46Z"},{"id":"https://www.aaron-gustafson.com/notebook/accessibility-assistant-for-figma-v52/","title":"✍🏻 Accessibility Assistant for Figma v52","summary":"I just hit “publish” on Accessibility Assistant for Figma v52 and I wanted to share some details on why this is a monumental release for us.","content_html":"<p>I just hit “publish” on <a href=\"https://www.figma.com/community/plugin/731310036968334777/accessibility-assistant\">Accessibility Assistant for Figma</a> v52 and I wanted to share some details on why this is a monumental release for us.</p>\n<p>We’re in the process of a major overhaul to this plugin. There was a lot of infrastructural work to do to modernize the plugin and set the stage for a host of new features to make designers more productive when it comes to making their designs more accessible. This release incorporates a lot of that foundational work, notably:</p>\n<ul>\n<li>Annotations are now presented as Figma-native Dev Mode annotations; this greatly reduces the working overhead of the plugin and reduces visual clutter in the document. We’ve also color-coordinated the icons in the Annotation Set viewer to the labels you see in the Dev Mode annotations, making it easier to scan.</li>\n<li>Legacy annotation tables will automatically be migrated into the new system. The visual readout tables will be hidden when this happens, but are still accessible if you need to copy or reference them. We’ve also included a tool to clean up these old layers when you’re ready.</li>\n<li>Annotations are now managed in a single UI rather than being separated, based on whether they impact focus order. This means you don’t need to jump back &amp; forth between tools to properly annotate your designs.</li>\n<li>We’ve organized and expanded the list of W3C roles available in the role picker. Additionally, the form now adapts to the role, offering you only the relevant fields and reducing distraction. We also added a description field, should you need it.</li>\n</ul>\n<p>We also fixed bugs related to duplicating layers. You can now copy layers and the annotations will go along for the ride, becoming a new Annotation Set. Similarly, you can now duplicate pages and the annotations — which are page-bound — will be re-generated. It’s worth noting that this may take some time on particularly large pages.</p>\n<p>This release has been a long time coming, but I’m incredibly proud of the team that’s been working so diligently on this, particularly Ashish Singh from HCL and Michael Fairchild, Scott O’Hara, and Ben Truelove from Microsoft. Their attention to detail and encyclopedic knowledge of accessibility has been instrumental in getting this project to the place that it is.</p>\n<p>And there’s more to come!</p>\n","social_text":"I just hit “publish” on Accessibility Assistant for Figma v52 and I wanted to share some details on why this is a monumental release for us.","url":"https://www.aaron-gustafson.com/notebook/accessibility-assistant-for-figma-v52/","tags":["accessibility","design","inclusive design","Microsoft","user experience","WAI-ARIA"],"date_published":"2026-02-20T23:27:28Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/some-blind-fans-to-experience-super-bowl-with-tactile-device-that-tracks-ball/","title":"🔗 Some blind fans to experience Super Bowl with tactile device that tracks ball","content_html":"<p>A few years ago, a couple students at the University of Washington asked me to come to their campus for a visit. They gave me a demo of an early prototype they’d been working on — a haptic feedback device that could allow someone who is Blind or low vision to follow a game. The demo took video data from a tennis match and mapped it onto the haptic tablet. It felt like Pong, but they had a bolder vision — tackling fast-moving and complicated sports like basketball, football, American football, and hockey.</p>\n<p>I immediately invited them to pitch us for the AI for Accessibility Grant Program that I ran for Microsoft. With so much focus on assistive technology to enable folks to work and accomplish common life tasks, I loved that the OneCourt team was interested in enabling people with disabilities to enjoy leisure activities like sporting events. Moreover, I saw the potential to enable Blind and low-vision parents to experience their kids’ sporting events, which could be life-changing for them.</p>\n<p>Needless to say, they wowed both me and the rest of the seleciton committee. We funded them to expand their prototypes and pursue partnerships with different professional sports leagues, teams, and venues. They were ambitious and it’s paying off.</p>\n<p>Fast forward a few years and they’re enabling a handful of Blind &amp; low vision sports fans to exerience the Super Bowl in a whole new way, using their technology. It’s amazing and I could not be more proud of them.</p>\n<p>Congrats y’all!</p>\n","social_text":"So proud of the OneCourt team for their work in bringing more leisure opportunities to the Blind & low vision community.","url":"https://www.aaron-gustafson.com/notebook/links/some-blind-fans-to-experience-super-bowl-with-tactile-device-that-tracks-ball/","external_url":"https://apnews.com/article/nfl-blind-fans-super-bowl-6daf12a08127c46c23dab6100a659681","tags":["accessibility","inclusive design","AI/ML"],"image":"https://dims.apnews.com/dims4/default/9b439cc/2147483647/strip/true/crop/5333x3554+0+1/resize/980x653!/quality/90/?url=https%3A%2F%2Fassets.apnews.com%2F1b%2Fe5%2F28e0bd88c1be654d380ee1c3b2f2%2F9a7b2e31c9464fa6a86eb6d04b0a3266","date_published":"2026-02-06T19:40:06Z"},{"id":"https://www.aaron-gustafson.com/notebook/fullscreen-video-and-iframes-made-easy/","title":"✍🏻 Fullscreen Video and Iframes Made Easy","summary":"The fullscreen-control web component adds fullscreen capabilities to any video or iframe element with a single wrapper and zero configuration.","content_html":"<p>Adding fullscreen capabilities to videos and embedded iframes shouldn’t require wrestling with prefixed APIs or managing focus states. The <code>fullscreen-control</code> web component handles all of that for you — just wrap it around the element. The component handles the rest as a discrete progressive enhancement.</p>\n<h2 id=\"easy-peasy\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#easy-peasy\" aria-hidden=\"true\">#</a> Easy-peasy</h2>\n<p>Here’s a simple example using a <code>video</code> element:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fullscreen-control</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>video</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>video.mp4<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>video</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fullscreen-control</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>With that in place, the component</p>\n<ul>\n<li>Adds a styleable button for launching fullscreen control over the contained element,</li>\n<li>Handles browser prefixes as needed,</li>\n<li>Manages focus automatically,</li>\n<li>Rigs up the necessary keyboard events (e.g. <kbd>Escape</kbd> to exit), and</li>\n<li>Assigns the relevant ARIA attributes.</li>\n</ul>\n<p>The component uses light DOM, so your <code>video</code> stays in the regular DOM tree and all your existing CSS continues to work.</p>\n<h2 id=\"fullscreen-iframes\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#fullscreen-iframes\" aria-hidden=\"true\">#</a> Fullscreen iframes</h2>\n<p>Need to embed a YouTube video, slide deck, or code demo? The component works with <code>iframe</code> elements too:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fullscreen-control</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>iframe</span>\n    <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://www.youtube.com/embed/dQw4w9WgXcQ<span class=\"token punctuation\">\"</span></span>\n    <span class=\"token attr-name\">width</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>560<span class=\"token punctuation\">\"</span></span>\n    <span class=\"token attr-name\">height</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>315<span class=\"token punctuation\">\"</span></span>\n    <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>YouTube video player<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>iframe</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fullscreen-control</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The component automatically adds the necessary <code>allow=&quot;fullscreen&quot;</code> and <code>allowfullscreen</code> attributes, including prefixed versions for broader compatibility.</p>\n<h2 id=\"customizable-button-text\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#customizable-button-text\" aria-hidden=\"true\">#</a> Customizable <code>button</code> text</h2>\n<p>You can change the <code>button</code> label to match your site’s language or writing style by setting the <code>button-text</code> attribute:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fullscreen-control</span> <span class=\"token attr-name\">button-text</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>全画面表示<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>video</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>video.mp4<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>video</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fullscreen-control</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The default button label is “View fullscreen,” but you can use this attribute to customize it to anything you like. You can even dynamically inject the accessible name of the contained element, using the <code>{name}</code> token. For example:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fullscreen-control</span> <span class=\"token attr-name\">button-text</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>View {name} fullscreen<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>video</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>video.mp4<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">aria-label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Product demo<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>video</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fullscreen-control</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This creates a <code>button</code> with the text “View Product demo fullscreen”. The component looks for <code>aria-label</code>, <code>title</code>, or other native naming on the wrapped element and uses that to make the <code>button</code> contextual.</p>\n<h2 id=\"distinct-screen-reader-labels\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#distinct-screen-reader-labels\" aria-hidden=\"true\">#</a> Distinct screen reader labels</h2>\n<p>If you want the visible label and accessible button name to differ, use the <code>button-label</code> attribute. Like <code>button-text</code>, it can also inject the accessible name of the controlled element using the <code>{name}</code> token:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fullscreen-control</span>\n  <span class=\"token attr-name\">button-text</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Fullscreen<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">button-label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>View {name} in fullscreen mode<span class=\"token punctuation\">\"</span></span>\n<span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>iframe</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://example.com<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Product teaser<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>iframe</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fullscreen-control</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This code will generate a <code>button</code> that visually reads “Fullscreen”, but is announced as “View Product teaser in fullscreen mode” to screen readers. In mode cases, <code>button-text</code> will suffice, but this option is available if you need to distinguish the buttons of multiple fullscreen controls from one another and don’t have visual space to display their accessible names.</p>\n<h2 id=\"focus-management\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#focus-management\" aria-hidden=\"true\">#</a> Focus management</h2>\n<p>If users activate fullscreen using the button, focus will automatically return to the button upon exiting fullscreen. This ensures keyboard users don’t lose their place.</p>\n<h2 id=\"need-more-control%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#need-more-control%3F\" aria-hidden=\"true\">#</a> Need more control?</h2>\n<p>Want to manage the component yourself? The component exposes three methods:</p>\n<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> control <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fullscreen-control\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Enter fullscreen</span>\n<span class=\"token keyword\">await</span> control<span class=\"token punctuation\">.</span><span class=\"token function\">enterFullscreen</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Exit fullscreen</span>\n<span class=\"token keyword\">await</span> control<span class=\"token punctuation\">.</span><span class=\"token function\">exitFullscreen</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Toggle fullscreen state</span>\ncontrol<span class=\"token punctuation\">.</span><span class=\"token function\">toggleFullscreen</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>These handle all the browser prefixes and error handling for you.</p>\n<p>There are also a set of events you can tap into when the fullscreen state changes:</p>\n<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> control <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fullscreen-control\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\ncontrol<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fullscreen-control:enter\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Entered fullscreen mode\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\ncontrol<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fullscreen-control:exit\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Exited fullscreen mode\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>These events give you the ability to pause other media, track analytics, and the like.</p>\n<h2 id=\"style-the-button\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#style-the-button\" aria-hidden=\"true\">#</a> Style the button</h2>\n<p>Since the component uses light DOM, you can style the button directly with CSS:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">fullscreen-control button</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">background</span><span class=\"token punctuation\">:</span> #ff6b6b<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> white<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">border</span><span class=\"token punctuation\">:</span> none<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> 0.75rem 1.5rem<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">border-radius</span><span class=\"token punctuation\">:</span> 20px<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">font-weight</span><span class=\"token punctuation\">:</span> bold<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token selector\">fullscreen-control button:hover</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">background</span><span class=\"token punctuation\">:</span> #ff5252<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>The button is positioned absolutely by default (top-right corner), but you can adjust this with CSS custom properties:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">fullscreen-control</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">--fullscreen-control-button-inset-block-start</span><span class=\"token punctuation\">:</span> 1rem<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">--fullscreen-control-button-inset-inline-end</span><span class=\"token punctuation\">:</span> 1rem<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>This uses logical properties, so it adapts automatically to different writing modes.</p>\n<h2 id=\"installation\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#installation\" aria-hidden=\"true\">#</a> Installation</h2>\n<p>Install via npm:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> @aarongustafson/fullscreen-control</code></pre>\n<p>Then import it in your JavaScript:</p>\n<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token string\">\"@aarongustafson/fullscreen-control/define.js\"</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Or load it from a CDN for quick prototyping:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>module<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n  <span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> defineFullscreenControl <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"https://unpkg.com/@aarongustafson/fullscreen-control@latest/define.js?module\"</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function\">defineFullscreenControl</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"browser-support\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#browser-support\" aria-hidden=\"true\">#</a> Browser support</h2>\n<p>The component uses modern web standards (Custom Elements v1, ES Modules) and handles browser-prefixed fullscreen APIs internally. For older browsers, you may need polyfills, but the component gracefully handles missing APIs with console warnings rather than breaking your page.</p>\n<h2 id=\"demo-and-source-code\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#demo-and-source-code\" aria-hidden=\"true\">#</a> Demo and source code</h2>\n<p>Check out the <a href=\"https://aarongustafson.github.io/fullscreen-control/demo/\">live demo</a> to see all the features in action, or grab the code from <a href=\"https://github.com/aarongustafson/fullscreen-control\">GitHub</a>.</p>\n","social_text":"Add fullscreen controls to videos and iframes with progressive enhancement. One wrapper, zero hassle.","url":"https://www.aaron-gustafson.com/notebook/fullscreen-video-and-iframes-made-easy/","tags":["web components","progressive enhancement","HTML","video","accessibility","media"],"date_published":"2025-12-29T17:17:27Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/forrester-research-as-technology-has-evolved-so-has-the-need-for-accessibility/","title":"🔗 Forrester Research: As technology has evolved, so has the need for accessibility","content_html":"<p>A recent paper from Forrester (commissioned by Microsoft, my employer), has confirmed my anedotal experiences are not outliers:</p>\n<blockquote>\n<p>This new study, based on a 2025 online survey of 3,901 US consumers, confirms what many of us know: accessible technology empowers everyone. And with the rise of AI, we’re entering a new era of possibility.</p>\n</blockquote>\n<p>One of the stats that’s likely to be surprising to many people is that people who identify as having disabilities and those who don’t both use assistive technology features at nearly the same rate.</p>\n<p>Full details of the research report are here: <a href=\"https://aka.ms/ForresterAccessibility2025\">Oh, The Things We Can Do Together — How Assistive Technology Is Unlocking Human Potential In The Era Of AI</a></p>\n","social_text":"“Accessible technology empowers everyone. And with the rise of AI, we’re entering a new era of possibility.”","url":"https://www.aaron-gustafson.com/notebook/links/forrester-research-as-technology-has-evolved-so-has-the-need-for-accessibility/","external_url":"https://blogs.microsoft.com/accessibility/forrester-research-2025/","tags":["accessibility","AI/ML"],"image":"https://blogs.microsoft.com/wp-content/uploads/sites/172/2025/11/Forrester-Accessibility-Report-Cover-1024x576.jpg","date_published":"2025-12-05T17:46:26Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/creating-a-more-accessible-web-with-aria-notify/","title":"🔗 Creating a more accessible web with ARIA Notify","content_html":"<p>I just saw this very exciting announcement on the Edge Dev Blog:</p>\n<blockquote>\n<p>ARIA Notify is an ergonomic and predictable way to tell assistive technologies (ATs), such as screen readers, exactly what to announce to users and when.</p>\n<p>In its simplest form, developers can call the ariaNotify() method with the text to be announced to the user.</p>\n</blockquote>\n<p>Here’s what it looks like:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token comment\">// Dispatch a normal priority notification</span>\ndocument<span class=\"token punctuation\">.</span><span class=\"token function\">ariaNotify</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Background task completed\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">priority</span><span class=\"token operator\">:</span> <span class=\"token string\">\"normal\"</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I’m particularly excited by this because of how much it simplifies the update process for engineers. Previously they needed to manage upates to an <code>aria-live</code> DOM node with the appropriate announcement level and hope for the best. This approach was plagued with issues ranging from lag — because, DOM manipulation — to confusion between whether “polite” or “assertive” was the right choice.</p>\n<p>The ARIA Notify proposal is clear, concise, and far more likely to get used and — more importantly — used properly.</p>\n<p>It’s currently in Origin Trial. Please give your feedback so we can get this into every browser sooner rather than later.</p>\n","social_text":"ARIA Notify looks like it could solve a lot of problems with screen reader announcements by simplifying the process.","url":"https://www.aaron-gustafson.com/notebook/links/creating-a-more-accessible-web-with-aria-notify/","external_url":"https://blogs.windows.com/msedgedev/2025/05/05/creating-a-more-accessible-web-with-aria-notify/","tags":["accessibility","JavaScript"],"date_published":"2025-11-26T18:40:45Z"},{"id":"https://www.aaron-gustafson.com/notebook/identifying-accessibility-data-gaps-in-codegen-models/","title":"✍🏻 Identifying Accessibility Data Gaps in CodeGen Models","summary":"I probed an LLM’s responses to HTML code generation prompts to assess its adherence to accessibility best practices. The results showed key areas where better training data is needed.","content_html":"<p>Late last year, I probed an LLM’s responses to HTML code generation prompts to assess its adherence to accessibility best practices. The results were unsurprisingly disappointing — roughly what I’d expect from a developer aware of accessibility but unsure how to implement it. The study highlighted key areas where training data needs improvement.</p>\n<h2 id=\"why-take-on-this-challenge%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#why-take-on-this-challenge%3F\" aria-hidden=\"true\">#</a> Why take on this challenge?</h2>\n<p>I get it — you probably rolled your eyes at yet another “AI and accessibility” post. Maybe you think AI-assisted coding is overhyped, environmentally harmful, unreliable, or just plain dangerous for our craft. I share many of those concerns. But here’s the thing: whether we like it or not, codegen models aren’t going anywhere. GitHub Copilot has millions of users, and tools like Claude Code and Cursor are rapidly gaining popularity.</p>\n<p>So we have a choice: we can complain about the inevitable tide of AI-generated garbage code, or we can get in there and figure out how to make it better — especially when it comes to accessibility.</p>\n<p>We’re facing a looming wave of inaccessible code that will be extremely difficult to remediate later. The foundation models are already being trained on the collective output of the web’s development community — a community that doesn’t have a high bar high for accessibility already. Codegen models are a massive consultancy staffed with <a href=\"https://christianheilmann.com/2015/07/17/the-full-stackoverflow-developer/\">full StackOverflow developers</a>. We need to figure out how to make them part of the solution, not part of the problem.</p>\n<p>It’s also worth noting that the better we make the output of these models, the fewer bugs will be generated. That, in turn, means fewer accessibility issues to fix later. If we don’t, there are plenty of AI-assisted scanners out there happy to burn the rainforest to find and remediate the bugs after the fact. We risk doubling the environmental impact—once to generate the bug, and again to fix it. That’s not the future I want. The reality here is that the only way to deal with this flood of AI-generated code is to make sure it’s good code in the first place.</p>\n<h2 id=\"how-did-i-conduct-my-research%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#how-did-i-conduct-my-research%3F\" aria-hidden=\"true\">#</a> How did I conduct my research?</h2>\n<p>Rather than relying on anecdotal evidence or cherry-picked examples, I built a systematic approach to evaluate how well LLMs — starting with GPT-4 — generate accessible HTML. The methodology is straightforward but comprehensive: I created a Python testing framework that sent carefully crafted prompts to Azure OpenAI’s GPT 4 model, collected the generated HTML responses, and then manually analyzed these responses for accessibility compliance.</p>\n<p>Here’s how it works:</p>\n<p><strong>Prompt Engineering</strong>: I designed prompts that ask for specific UI components—form fields, navigation menus, interactive elements—without explicitly mentioning accessibility requirements. This gives us a baseline of what the model considers “standard” output. I included one prompt that specifically requested accessibility features to see if the model could improve when guided. I suspected it would often add ARIA attributes without addressing underlying issues, but I wanted to validate that too.</p>\n<p><strong>Response Collection</strong>: For each prompt, I generated 10 iterations at high temperature (0.95) to capture the model’s range of responses. Each unique response got saved as an individual HTML file for analysis.</p>\n<p><strong>Systematic Analysis</strong>: I manually review each generated code snippet, cataloging accessibility errors, warnings, and missed opportunities. I tried using the LLM as a judge, but even with a detailed rubric, the results were poor. My eval looked specifically for things like:</p>\n<ul>\n<li>Improper semantic HTML usage</li>\n<li>Missing or incorrect ARIA attributes</li>\n<li>Keyboard navigation issues</li>\n<li>Screen reader compatibility problems</li>\n<li>Form labeling errors</li>\n</ul>\n<p>When I identified errors, I remediated them and committed the remediated file to the repo with a commit message that included all of the issues and warnings on its own line.</p>\n<p><strong>Diff-Based Retesting</strong>: I wanted to see if diff data could improve future codegen requests, so I created a tool to generate a collection of <code>.diff</code> files for each pattern that included the commit message as a header in each file. I then used those diff files as part of a new instance of the prompt to test whether the model can improve its output when guided.</p>\n<h2 id=\"what-did-i-learn%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#what-did-i-learn%3F\" aria-hidden=\"true\">#</a> What did I learn?</h2>\n<p>After analyzing hundreds of generated code snippets, the results are sobering. The model consistently demonstrates what I’d describe as superficial awareness without true understanding — it knows accessibility concepts exist but fundamentally misunderstands their purpose and proper implementation.</p>\n<p>Here are some of the patterns I’ve documented:</p>\n<p><strong>Form Label Disasters</strong>: When asked to create a required text field, the model failed to include a visible label:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span>\n  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>text<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>orangeColor<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>orangeColor<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">required</span>\n  <span class=\"token attr-name\">placeholder</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>What color is an orange?<span class=\"token punctuation\">\"</span></span>\n<span class=\"token punctuation\">/></span></span></code></pre>\n<p>Sure, the <code>placeholder</code> attribute is there, and in a pinch it will be included in a field’s accessible name calculation, but sighted users will lose the label as soon as they start typing.</p>\n<p><strong>ARIA Attribute Confusion</strong>: The model would routinely involve ARIA for no reason:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>color-question<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token punctuation\">></span></span>What color is an orange? <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span> <span class=\"token special-attr\"><span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span><span class=\"token value css language-css\"><span class=\"token property\">color</span><span class=\"token punctuation\">:</span> red<span class=\"token punctuation\">;</span></span><span class=\"token punctuation\">\"</span></span></span><span class=\"token punctuation\">></span></span>*<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span>\n<span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span>\n  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>text<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>color-question<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>color-question<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">required</span>\n  <span class=\"token attr-name\">aria-required</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>true<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">aria-labelledby</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>color-question<span class=\"token punctuation\">\"</span></span>\n<span class=\"token punctuation\">/></span></span></code></pre>\n<p>Here the <code>for</code> attribute already establishes the relationship between the label and input, so <code>aria-labelledby</code> is redundant. A bit of a nitpick, but the <code>aria-required=&quot;true&quot;</code> is also unnecessary since the native <code>required</code> attribute already conveys that information to assistive technologies. <code>aria-required=&quot;true&quot;</code> is only needed when creating custom form controls non-semantic markup.</p>\n<p><strong>Redundant ARIA</strong>: Keeping on the ARIA redundancy, consider examples like this:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span>\n  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>radio<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>option1<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">aria-labelledby</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>label1<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">aria-label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Option 1<span class=\"token punctuation\">\"</span></span>\n<span class=\"token punctuation\">/></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>option1<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>label1<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Option 1<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This redundancy raises the question <em>why‽</em></p>\n<p><strong>Required Field Misapplication</strong>: For checkbox groups where users need to select “one or more,” the model often adds <code>required</code> to individual checkboxes:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fieldset</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>legend</span><span class=\"token punctuation\">></span></span>What fruits do you like?<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>legend</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span>\n      <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>checkbox<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>bananas<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>fruits<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>bananas<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">required</span>\n    <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>bananas<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Bananas<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span>\n      <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>checkbox<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>oranges<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>fruits<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>oranges<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\">required</span>\n    <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>oranges<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Oranges<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>checkbox<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>apples<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>fruits<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>apples<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">required</span> <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>apples<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Apples<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token special-attr\"><span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span><span class=\"token value css language-css\"><span class=\"token property\">color</span><span class=\"token punctuation\">:</span> red<span class=\"token punctuation\">;</span> <span class=\"token property\">display</span><span class=\"token punctuation\">:</span> none<span class=\"token punctuation\">;</span></span><span class=\"token punctuation\">\"</span></span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>validation-error<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n    You must choose one or more fruits\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fieldset</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This breaks the intended behavior—if any checkbox is marked required, it must be checked for form validation to pass. For a web component that addresses this limitation in HTML, see my post “<a href=\"/notebook/requirement-rules-for-checkboxes/\">Requirement Rules for Checkboxes</a>.”</p>\n<p><strong>Grouped Field Confusion</strong>: Not understanding when to use <code>fieldset</code> and <code>legend</code> (or at least using <code>role=&quot;group&quot;</code> and <code>aria-labelledby</code>) on a field group:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span><span class=\"token punctuation\">></span></span>Select Theme:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>radio<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>light<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>theme<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>light<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>light<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Light<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>radio<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>dark<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>theme<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>dark<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>dark<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Dark<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>radio<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>high-contrast<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>theme<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>high-contrast<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>high-contrast<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>High Contrast<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>You can change this later<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Ideally, this would be a <code>fieldset</code> with a <code>legend</code> and the descriptive text would appear right after the <code>legend</code> and be associated with the group using <code>aria-describedby</code>.</p>\n<p><strong>Color-Only Error Indication</strong>: Generating error states that rely solely on color changes without text indicators or proper ARIA attributes to convey the error state to screen readers.</p>\n<p><strong>Unnecessary Role Additions</strong>: Adding redundant roles like <code>role=&quot;radiogroup&quot;</code> to properly structured fieldsets containing radio inputs, where the native semantics already provide the correct accessibility tree.</p>\n<p><strong>Missing Error State Management</strong>: Failing to include <code>aria-invalid=&quot;true&quot;</code> on fields with errors or properly associate error messages with their corresponding form controls.</p>\n<p><strong>Lack of Wayfinding Help</strong>: Failing to include navigational labels and <code>aria-current=&quot;page&quot;</code> in a breadcrumb nav.</p>\n<p><strong>Adding Unnecessary JavaScript</strong>: Even though it was instructed to only generate JavaScript when absolutely necessary, the model would often inject JavaScript for simple tasks that could be handled with HTML and CSS alone.</p>\n<h2 id=\"how-does-this-help%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#how-does-this-help%3F\" aria-hidden=\"true\">#</a> How Does This Help?</h2>\n<p>Here’s where things get interesting — and hopeful. When I retested using prompts that included accessibility hints, the model’s output improved dramatically. Not just slightly better, but often going from fundamentally broken to genuinely accessible.</p>\n<p>For example, when I added diff data related to fieldset use to a prompt about radio button groups, the model switched from generating meaningless <code>div</code> wrappers to proper semantic structures.</p>\n<p>This suggests the model can produce quality code if properly primed. It also indicates that the training data likely lacks sufficient examples of well-implemented accessible components. If the model had been trained on a richer dataset of accessible code, it might not need such explicit guidance to produce good results.</p>\n<h2 id=\"where-do-we-go-from-here%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#where-do-we-go-from-here%3F\" aria-hidden=\"true\">#</a> Where Do We Go From Here?</h2>\n<p>These findings point to several concrete approaches for improving accessibility in AI-generated code:</p>\n<p><strong>Enhanced Training Data</strong>: The models need exposure to more high-quality, accessible code examples. Current training data clearly overrepresents inaccessible implementations. We need comprehensive datasets of properly implemented accessible components across different frameworks and use cases.</p>\n<p><strong>Accessibility-Aware Fine-Tuning</strong>: Post-training refinement specifically focused on accessibility compliance could help models prioritize inclusive patterns. This could involve training on accessibility-annotated code pairs — showing inaccessible implementations alongside their accessible counterparts, like the diffs do.</p>\n<p><strong>Prompt Engineering Guidelines</strong>: Tool creators should integrate accessibility considerations into their default system prompts. Instead of just asking for “clean, semantic HTML,” prompts should provide detailed instructions to demonstrate accessibility best practices rather than pointing at often vague guidelines like WCAG.&quot;</p>\n<p><strong>Integrated Accessibility Validation</strong>: IDE integrations should include real-time accessibility linting of AI-generated code, providing immediate feedback and suggestions for improvement.</p>\n<p><strong>Community-Contributed Training Data</strong>: We should coordinate our efforts to produce an open source, high-quality accessible code dataset so that this data can be integrated into future models.</p>\n<hr>\n<p>The data from this project provides a roadmap for where to focus these efforts. We’re not dealing with models that are fundamentally incapable of generating accessible code — we’re dealing with models that haven’t been properly trained to prioritize accessibility by default.</p>\n<h2 id=\"want-to-get-involved%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#want-to-get-involved%3F\" aria-hidden=\"true\">#</a> Want to Get Involved?</h2>\n<p>If you want to conduct similar evaluations with your preferred models or specific use cases, I’ve created a template repository with the testing framework: <a href=\"https://github.com/aarongustafson/CodeGen-Model-Eval-and-Refine-Tools\">CodeGen Model Eval and Refine Tools</a>. It includes the Python testing harness, prompt templates, and analysis guidelines to get you started.</p>\n<p>The complete findings, methodology details, and code samples for my research are available <a href=\"https://github.com/aarongustafson/testing-llm-code-a11y\">on GitHub</a>. I encourage you to dig into the data — it’s eye-opening and frustrating, yes, but ultimately actionable.</p>\n<p>There are other projects and research exploring this space as well. A few worth checking out:</p>\n<ul>\n<li><a href=\"https://aimac.ai/\">AIMAC</a> - The AI Model Accessibility Checker (AIMAC) Leaderboard measures how well LLMs generate accessible HTML pages using neutral prompts without specific accessibility guidance. Checks are performed with axe-core.</li>\n<li><a href=\"https://github.com/microsoft/a11y-llm-eval\">A11y LLM Evaluation Harness and Dataset</a> - A more recent research project to evaluate how well various LLM models generate accessible HTML content.</li>\n</ul>\n<hr>\n<p>We’re at a critical moment where the patterns established in AI-assisted development will shape the accessibility of the web for years to come. We can either let this technology amplify existing accessibility problems, or we can tackle the problems head-on and be part of the solution.</p>\n","social_text":"I probed an LLM’s responses to HTML code generation prompts to assess its adherence to accessibility best practices. The results showed key areas where better training data is needed.","url":"https://www.aaron-gustafson.com/notebook/identifying-accessibility-data-gaps-in-codegen-models/","tags":["accessibility","AI/ML","HTML"],"image":"https://www.aaron-gustafson.com/i/posts/2025-10-15/hero.png","date_published":"2025-10-16T19:12:02Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/designing-for-distress-understanding-users-in-crisis/","title":"🔗 Designing for Distress: Understanding Users in Crisis","content_html":"<blockquote>\n<p>In a distressing moment, it’s like you’re rushing to the airport — you’re just looking for help right now. When you aren’t distressed, it’s like you’re on vacation. You can take your time, you’re more open to exploring.</p>\n</blockquote>\n<p>In a recent study, the VA learned a lot from users navigating acute distress — and why typical UX patterns fail. This is highly recommended reading for anyone working in the design space.</p>\n","social_text":"In a recent study, the VA learned a lot from users navigating acute distress — and why typical UX patterns fail.","url":"https://www.aaron-gustafson.com/notebook/links/designing-for-distress-understanding-users-in-crisis/","external_url":"https://medium.com/@codybolandphd/designing-for-distress-understanding-users-in-crisis-0e02466f1f5b","tags":["accessibility","user experience"],"date_published":"2025-10-10T18:52:07Z"},{"id":"https://www.aaron-gustafson.com/appearances/podcasts/accessibility-in-automated-systems/","title":"🎧 Accessibility in Automated Systems","content_html":"<p>I chatted with Sharon Steed on a variety of topics ranging from accessibility to diversity, representation, AI, politics, the future, and more.</p>\n","url":"https://www.linkedin.com/video/live/urn:li:ugcPost:7330624084201852928/","tags":["accessibility","AI/ML","empathy","inclusion","the future"],"date_published":"2025-05-20T00:00:00Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/disability-personas-from-a-web-for-everyone/","title":"🔗 Disability Personas from A Web for Everyone","summary":"The disability personas contained in Sarah Horton &amp;amp; Whitney Quesenbery’s A Web for Everyone are a terrific resource, so I’m thrilled their available beyond the book now too.","content_html":"<p>The disability personas contained in Sarah Horton &amp; Whitney Quesenbery’s <cite>A Web for Everyone</cite> are a terrific resource, so I’m thrilled their available beyond the book now too.</p>\n","social_text":"I ❤️ these disability personas. What an amazing resource!","url":"https://www.aaron-gustafson.com/notebook/links/disability-personas-from-a-web-for-everyone/","external_url":"https://knowaboutaccessibility.org/category/resources/","tags":["accessibility","inclusive design","user experience"],"date_published":"2025-05-09T23:05:56Z"},{"id":"https://www.aaron-gustafson.com/notebook/passing-your-css-theme-to-canvas/","title":"✍🏻 Passing Your CSS Theme to `canvas`","summary":"While working on a recent project I noticed an issue with a <code>canvas</code>-based audio visualization when I toggled between light and dark modes. I couldn’t find any articles on to make <code>canvas</code> respond nicely to user preferences, so I thought I’d share (in brief) how I solved it.","content_html":"<p>While working on a recent project I noticed an issue with a <code>canvas</code>-based audio visualization when I toggled between light and dark modes. When I’d originally set it up I was browsing in dark mode and the light visualization stroke showed up perfectly on the dark background, but it was invisible when viewed using the light theme (which I’d neglected to test). I searched around, but didn’t find any articles on easy ways to make <code>canvas</code> respond nicely to user preferences, so I thought I’d share (in brief) how I solved it.</p>\n<h2 id=\"the-css-setup\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#the-css-setup\" aria-hidden=\"true\">#</a> The CSS Setup</h2>\n<p>The theming of this particular project uses <a href=\"https://developer.mozilla.org/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties\">CSS custom properties</a>. For simplicty I’m going to set up two named colors and then use two theme-specific custom properties to apply them in the default light theme and the dark theme:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">:root</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">--color-dark</span><span class=\"token punctuation\">:</span> #222<span class=\"token punctuation\">;</span>\n  <span class=\"token property\">--color-light</span><span class=\"token punctuation\">:</span> <span class=\"token function\">rgba</span><span class=\"token punctuation\">(</span>255<span class=\"token punctuation\">,</span> 255<span class=\"token punctuation\">,</span> 255<span class=\"token punctuation\">,</span> 0.5<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token property\">--color-background</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--color-light<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token property\">--color-foreground</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--color-dark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span><span class=\"token property\">prefers-color-scheme</span><span class=\"token punctuation\">:</span> dark<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token selector\">:root</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">--color-background</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--color-dark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token property\">--color-foreground</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--color-light<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"applying-the-theme-to-canvas\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#applying-the-theme-to-canvas\" aria-hidden=\"true\">#</a> Applying the Theme to Canvas</h2>\n<p>To get the theme into my <code>canvas</code>-related code, I set up a <code>theme</code> object to hold the values:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">const</span> theme <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Next, I wrote a function to pull in the theme colors using <a href=\"https://developer.mozilla.org/docs/Web/API/Window/getComputedStyle\"><code>window.getComputedStyle()</code></a>. After defining the function, I call it immediately to populate the <code>theme</code> object:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token function\">importTheme</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  theme<span class=\"token punctuation\">.</span>foreground <span class=\"token operator\">=</span>\n    window\n      <span class=\"token punctuation\">.</span><span class=\"token function\">getComputedStyle</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">getPropertyValue</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"--color-foreground\"</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">trim</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> <span class=\"token string\">\"black\"</span><span class=\"token punctuation\">;</span>\n  theme<span class=\"token punctuation\">.</span>background <span class=\"token operator\">=</span>\n    window\n      <span class=\"token punctuation\">.</span><span class=\"token function\">getComputedStyle</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">getPropertyValue</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"--color-background\"</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">trim</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> <span class=\"token string\">\"white\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token function\">importTheme</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I set this up with just two theme colors, but you can import as many (or few) as you like. Be sure to set a sensible default or fallback for each color though, just in case your theme’s custom property names change.</p>\n<p>With this in place, I can set my <code>canvas</code> animation’s colors by referencing them from the <code>theme</code> object. For example:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">context<span class=\"token punctuation\">.</span>fillStyle <span class=\"token operator\">=</span> theme<span class=\"token punctuation\">.</span>foreground<span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"keeping-things-in-sync\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#keeping-things-in-sync\" aria-hidden=\"true\">#</a> Keeping Things in Sync</h2>\n<p>The final bit of magic comes when you add an event listener to a <code>MediaQueryList</code>:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">const</span> mediaQuery <span class=\"token operator\">=</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">matchMedia</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"(prefers-color-scheme: dark)\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nmediaQuery<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"change\"</span><span class=\"token punctuation\">,</span> importTheme<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Here I’ve used <code>matchMedia()</code> to get a <code>MediaQueryList</code> object. Typically we use the <code>matches</code> property of this object to establish whether the media query currently matches or not. A lesser-known option, however, is that you can attach an event listener to it that will be triggered whenever the query’s status changes. So cool! With this in place, the <code>canvas</code> contents will update whenever the user’s theme changes. <a href=\"#fig-2025-05-01-01\">Here’s an example of that</a>:</p>\n<figure id=\"fig-2025-05-01-01\" class=\"media-container\">\n<p><a href=\"https://www.youtube.com/watch?v=pALIuO5uHUA\">https://www.youtube.com/watch?v=pALIuO5uHUA</a></p>\n<figcaption><p>This video demonstrates how a canvas element rendering a dark sine wave against a light background can miraculously transform into a light sine wave against a dark background using CSS custom properties and a bit of JavaScript.</p></figcaption>\n</figure>\n<h1 id=\"demo\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#demo\" aria-hidden=\"true\">#</a> Demo</h1>\n<p>I put together <a href=\"https://codepen.io/aarongustafson/pen/LEEQyqg\">a quick demo of this</a> in a fork of <a href=\"https://codepen.io/alvinshaw/pen/mdEKggg\">Alvin Shaw’s Canvas Sine Wave Experiment</a>:</p>\n<figure id=\"fig-2025-05-01-02\" class=\"media-container\">\n<iframe class=\"codepen\" height=\"331\" style=\"width:100%;\" scrolling=\"no\" title=\"CodePen Embed\" src=\"https://codepen.io/anon/embed/LEEQyqg?height=331&theme-id=dark&default-tab=result\" frameborder=\"0\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\"><p><a href=\"https://codepen.io/aarongustafson/pen/LEEQyqg\" target=\"_blank\" rel=\"noopener\">See the Pen</a></p></iframe></figure>\n<hr>\n<p>Hopefully this is helpful to someone out there. Happy theming!</p>\n","social_text":"Need to pipe your CSS theme into a `canvas` element? Here’s how I did it.","url":"https://www.aaron-gustafson.com/notebook/passing-your-css-theme-to-canvas/","tags":["accessibility","animation","CSS","design","JavaScript"],"date_published":"2025-05-01T21:49:27Z"},{"id":"https://www.aaron-gustafson.com/publications/books/learning-web-design-sixth-edition/","title":"📗 Learning Web Design","content_html":"<p>Do you want to build web pages but have no prior experience? This friendly guide is the perfect place to start. You'll begin at square one, learning how the web and web pages work, and then steadily build from there. By the end of the book, you'll have the skills to create a simple site with multicolumn pages that adapt for mobile devices.</p>\n","url":"https://www.oreilly.com/library/view/learning-web-design/9781098137670/","tags":["accessibility","CSS","HTML","JavaScript","progressive enhancement","responsive web design","web design","web development","web standards"],"date_published":"2025-05-01T00:00:00Z"},{"id":"https://www.aaron-gustafson.com/notebook/exploring-ais-role-in-accessibility-with-gymnasium/","title":"✍🏻 Exploring AI’s Role in Accessibility","summary":"I met up with Jeremy Osborne and Andrew Miller to talk about the benefits and harms of AI as it relates to accessibility.","content_html":"<p>Earlier this month I joined Jeremy Osborne and Andrew Miller to talk about the benefits and harms of AI as it relates to accessibility. It was livestreamed on a few platforms, but I wanted to drop links to the transcript and archival video in case you’re interested.</p>\n<figure>\n<p><a href=\"https://www.youtube.com/watch?v=7ObB4jM-QXU\">https://www.youtube.com/watch?v=7ObB4jM-QXU</a></p>\n</figure>\n<p><a href=\"https://github.com/gymnasium/exploring-ais-role-in-accessibility\">View the transcript</a></p>\n","social_text":"I met up with Jeremy Osborne and Andrew Miller to talk about the benefits and harms of AI as it relates to accessibility.","url":"https://www.aaron-gustafson.com/notebook/exploring-ais-role-in-accessibility-with-gymnasium/","tags":["accessibility","AI/ML"],"date_published":"2025-04-14T16:11:54Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/symbol-creator-ai/","title":"🔗 Symbol Creator AI","content_html":"<p>About a year ago, the folks at Global Symbols pitched me on their vision for using image generation models to create new AAC symbols that fit thematically within an existing set. It was a truly compelling use case for generative AI and I was thrilled to fund their project through the AI for Accessibility grant program.</p>\n<p>Fast forward to today and their project has launched! Please check it out and share it with any AAC users in your life!</p>\n","social_text":"I am incredibly excited about this: crowdsourced & AI-assisted symbol generation for #AAC users. Now people can create the symbols they need in their lives. #NoGatekeepers","url":"https://www.aaron-gustafson.com/notebook/links/symbol-creator-ai/","external_url":"https://scai.globalsymbols.com/","tags":["accessibility","AI/ML"],"date_published":"2025-04-07T22:14:51Z"},{"id":"https://www.aaron-gustafson.com/appearances/podcasts/2025-04-02-exploring-ais-role-in-accessibility/","title":"🎧 Exploring AI’s Role in Accessibility","content_html":"<p>I met up with Jeremy Osborne and Andrew Miller to talk about the benefits and harms of AI as it relates to accessibility.</p>\n","url":"https://www.youtube.com/live/7ObB4jM-QXU","tags":["accessibility","AI/ML"],"date_published":"2025-04-02T00:00:00Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/speech-accessibility-project-data-leads-to-recognition-improvements-on-microsoft-azure/","title":"🔗 Speech Accessibility Project data leads to recognition improvements on Microsoft Azure","content_html":"<p>This is the kind of work that keeps me excited about the potential of AI to meaningfully improve people’s lives. I’m so proud to be playing a small part in this project.</p>\n","social_text":"This is the kind of work that keeps me excited about the potential of AI to meaningfully improve people’s lives.","url":"https://www.aaron-gustafson.com/notebook/links/speech-accessibility-project-data-leads-to-recognition-improvements-on-microsoft-azure/","external_url":"https://speechaccessibilityproject.beckman.illinois.edu/article/2025/01/31/speech-accessibility-project-data-leads-to-recognition-improvements-on-microsoft-azure","tags":["accessibility","AI/ML"],"date_published":"2025-01-31T22:39:05Z"},{"id":"https://www.aaron-gustafson.com/notebook/on-diversity/","title":"✍🏻 On Diversity","summary":"Seeing the current U.S. administration taking an axe to DEI programs in the government and bully private businesses to do the same has me incredibly frustrated, confused, and (yes) angry. I want more equality and more opportunity in the world, not less.","content_html":"<p>I’ve been broadly working in the DEI (or DEIA if you like) sphere for decades now. Most of my work has been coming at it from the accessibility side of things, but I got really involved in allyship and more traditional DEI work starting in 2019. Seeing <a href=\"https://www.npr.org/2025/01/23/nx-s1-5271588/trump-dei-diversity-equity-inclusion-federal-workers-government\">the current U.S. administration taking an axe to DEI programs in the government</a> and <a href=\"https://www.forbes.com/sites/saradorn/2025/01/23/trumps-diversity-orders-rattle-ceos-what-companies-should-know-about-new-dei-rules/\">bully private businesses to do the same</a> has me incredibly frustrated, confused, and (yes) angry. I want more equality and more opportunity in the world, not less.</p>\n<p>And so, when I was listening to <a href=\"https://www.youtube.com/watch?v=mQwJuayXJ18\">the latest episode of <cite>The Weekly Show with Jon Stewart</cite></a>, I was struck by how the left and right may actually be more aligned on DEI than the headlines lead us to believe.</p>\n<p>In the episode, Stewart was interviewing former New Jersey Governor Chris Christie, a Republican. When the topic of DEI came up, they got into a discussion of merit vs. diversity in the context of the Secretary of Defense role. Both agreed that, in terms of merit, <a href=\"https://wikipedia.org/wiki/Lloyd_Austin\">General Lloyd Austin</a> was a much better hire than <a href=\"https://en.wikipedia.org/wiki/Pete_Hegseth\">Fox’s former weekend host Pete Hegseth</a>. The fact that Austin is also Black has no more impact on his being a better candidate than the fact that Pete Hegseth being White makes him a worse candidate. What Austin does bring to the table, however, is first-hand knowledge of what it’s like to rise up the ranks as a Black soldier. That’s a significant knowledge gap when it comes to the U.S. military, whose top brass isn’t representative of the diversity of its personnel.</p>\n<p>This is something that Christie actually points out when discussing becoming the U.S. Attorney in New Jersey back in 2002:</p>\n<blockquote>\n<p>When I got there, I just did a lot of walking around the office to see, <em>okay, who’s here?</em> Jon, it was the whitest, malest office I had ever been in in my life. And I was coming from private law practice.</p>\n</blockquote>\n<p>He, rightly, saw this as a problem and wanted to address it. He told his staff</p>\n<blockquote>\n<p>[We need] to go out and recruit candidates who are African-American, Latino, Asian, women. Bring them to me. If they’re not good, I’m not going to hire them. But I’m convinced we’re not seeing them.</p>\n</blockquote>\n<p>His approach to address this was perfectly rational and aligned with the approach Jon had discussed mere moments before:</p>\n<blockquote>\n<p>What I found was hiring has a certain inertia to it, right? Generally, the people that started whatever industry or whatever office did, generally hire close to people that resemble them. So I’m not even talking about White/Black. I’m talking about like… I’ll just go with late-night comedy, right?</p>\n<p>David Letterman revolutionized late-night comedy. He did it with a lot of Harvard, Lampoon, SNL, same way, writers. The comedy writing industry was for a long time — not necessarily out of malevolence or prejudice — the inertia of it, the status quo of it, was nerdy white dudes from Harvard and the other Ivy Leagues.</p>\n<p>But even when we went to like, “Oh, we’re going to do blind submissions,” what we didn’t realize is all the agents are also steeped in that same status quo. So all the resumes — even when we would get them — still predominantly [trails off]. When we went specifically to say — now, this is what you would consider DEI — “Give us not that. Open it up to make sure you give us women, people of color, other writers, so that we can at least see what that is.” And all of a sudden, we found these incredible writers. Now, you could say, “Oh, you put diversity over competence,” but that’s the red herring. We didn’t. We opened up what were stagnant pools. Pools that were incestuous. And we opened up those tributaries. Isn’t that what increases competition, not decreases it?</p>\n</blockquote>\n<p>What’s fascinating here is that they are both making the same point. As Christie says later</p>\n<blockquote>\n<p>We then went about this process of hiring a large number of African-American, Latino, and Asian prosecutors, but I would tell you that every one of them checked both boxes. They checked the box of, “they now look more like the community we represent than we did before.” And these are really good lawyers.</p>\n</blockquote>\n<p>So these two men from very different political viewpoints totally agree on the importance of <em>representation</em>. So where’s the issue?</p>\n<h2 id=\"the-issue-is-tokenism\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#the-issue-is-tokenism\" aria-hidden=\"true\">#</a> The Issue is Tokenism</h2>\n<p>When Stewart highlighted how aligned their two perspectives were and Christie pushed back, stating that DEI policies were problematic:</p>\n<blockquote>\n<p>I think there have been a number of areas where there are people who hire certain folks just for their diversity. I’ve seen it happen here in New Jersey, in the government since I left. Where people say, “I am going to make sure that I have one of every…” It’s almost like a half a Noah’s Ark. “I’m going to have one of these and one of these and one one of these and one of these.”</p>\n</blockquote>\n<p>Stewart questioned that:</p>\n<blockquote>\n<p>But you just told me that’s what you did in the prosecutor’s office.</p>\n</blockquote>\n<p>But Christie didn’t see it that way:</p>\n<blockquote>\n<p>No, what I did was get them in to interview them. If it turned out, Jon, that they were also really good lawyers, they got hired. I’m talking about something different. I’m talking about predetermining the outcome in the way that you just talked about — and I believe that legacy admissions predetermined the outcome — that there have been some in charge of government across this country who have predetermined determined outcomes and said, “I am going to have this many African-Americans, this many Latinos, this many Asians, this many lesbians, this many gay men…” I think that when people see that, they say to themselves, “That’s not right either.”</p>\n</blockquote>\n<p>What he’s talking about is what I’d call <em>performative DEI</em>. It’s not substantive, but attempts to give off the appearance of being so. It’s the DEI equivalent of <a href=\"https://wikipedia.org/wiki/Greenwashing\">greenwashing</a>.</p>\n<h2 id=\"dei-cannot-be-performative\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#dei-cannot-be-performative\" aria-hidden=\"true\">#</a> DEI Cannot be Performative</h2>\n<p>When people hire folks or celebrate folks for their diversity rather than their diversity plus their competence or talents, it undermines the legitimacy of DEI programs that are attempting to do what they both discussed being important: <em>representation</em>.</p>\n<p>As they both said, we need to <a href=\"https://blog.skill.jobs/screening-in-vs-screening-out-shifting-recruitment-strategies-for-better-hiring-outcomes/\">screen in</a> job applicants who wouldn’t otherwise consider applying for roles in our organizations. Christie talked about this too:</p>\n<blockquote>\n<p>The aha moment for me on that concept and why it was the right way to go was there was a young guy that I hired very early on: African-American, University of Michigan, University of Penn Law School, clerk for Alan Page — the former Minnesota Viking, defensive tackle in the Supreme Court of Minnesota— He’s from New Jersey, grew up in Maplewood. I said to him, “Why didn’t you ever apply here before?” He said, “Because I knew people like me wouldn’t get hired.”</p>\n</blockquote>\n<p>Hiring is just part of the process though. You can widen the applicant funnel and bring in a more representative — which is to say <em>diverse</em> — applicant pool with relatively little effort. Where things often fall short is retention.</p>\n<h2 id=\"is-your-organization-even-ready%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#is-your-organization-even-ready%3F\" aria-hidden=\"true\">#</a> Is Your Organization Even Ready?</h2>\n<p>If your organization isn’t excited at the prospect of a more diverse workforce and prepared to support them when they are onboarded, you need to press pause and get prepared. Similarly, if your company is eager, but very homogenous, you’ve also got work to do. No one wants to come into a job and feel like “the only” or “the token” anything. And even if they were the most qualified applicant for the position, some jackass will say something that implies they are. It’s a tale as old as time and you need to be prepared for that reality.</p>\n<p>The first thing you need to do is <em>educate</em>. You need to help folks on your team understand the gaps in your collective knowledge &amp; experience. They need to see that a more diverse team can help fill those gaps. The data that shows that <a href=\"https://www.forbes.com/councils/forbestechcouncil/2022/05/10/diverse-teams-achieve-greater-success-how-business-can-champion-diversity-as-good-sense/\">more diverse organizations are more successful</a>. Share that! I’m guessing most of your team is there because they want your organization to be as successful as possible.</p>\n<p>And make sure they understand the historical barriers folks from different communities have faced in getting access to jobs at organizations like yours… even when they were equally or more accomplished than folks from the dominant group. As Stewart said on the show:</p>\n<blockquote>\n<p>It’s not rigging [the system] in a different direction, it’s unrigging it.</p>\n</blockquote>\n<p>It’s also important to note that the process here needs to be inclusive as well… call people <em>in</em>, don’t call them <em>out</em>. Everyone is on their own journey and deserves the space to fail and learn from their mistakes. If someone says something offensive, let them know that it’s offensive and why. Tell them what they should say — if anything — instead.</p>\n<p>If you approach people with empathy, you’re much more likely to get a positive response. And, Twitter aside, most folks aren’t out in these streets trying to be trolls. People are a product of their own experiences and those experiences can be quite different from yours. Help your colleagues broaden their perspectives with positive reinforcement, not chastising.</p>\n<p>That said, you also need the proper mechanisms in place to address non-inclusive behaviors when they become a pattern or reach a certain threshold of severity. Those mechanisms need to outline the consequences for such behavior. The severity of the consequence needs to align with the severity of the harm, but it may need to escalate in severity for repeat offenses. Depending on the size of your organization, coming up with these policies and consequences could be a group activity to ensure both awareness and buy-in.</p>\n<h2 id=\"embrace-dei-and-pave-the-way-for-mediocrity\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#embrace-dei-and-pave-the-way-for-mediocrity\" aria-hidden=\"true\">#</a> Embrace DEI and Pave the Way for Mediocrity</h2>\n<p>To be clear, neither Jon Stewart nor the progressive left are pushing for diversity quotas like Christie seems to think they are. But there are folks out there who are. These performative DEI programs have got to go. As my colleague and friend Ebele Okoli says “bake it in, don’t cake it on.”</p>\n<p>Don’t hire or promote someone just because you think their headshot would help to <em><a href=\"https://www.merriam-webster.com/dictionary/melanated\">melanate</a></em> your About page. That’s not what DEI is about and it doesn’t help us to reverse the dire course the U.S. government and cowardly companies are taking currently. DEI needs to be a part of every process in your organization on order to give everyone — white men like me included — an equal chance to succeed.</p>\n<p>Cast a wide net. Hire and promote for competence <em>and</em> to address the knowledge gaps your team absolutely has. Foster an inclusive workplace that <em>values</em> the different lived experience and perspectives brought to the table by each and every employee. That is how you succeed with DEI. It’s also how DEI will help your organization succeed in its mission and grow to hire more folks.</p>\n<p>And as more of the incredibly talented people out there get hired on at organizations like yours, all boats will rise, creating more jobs and space for mediocre people of all stripes to get hired and rise up the ranks too. But they won’t get there just because or who they know, what they look like, or because they tick a particular box on your diversity bingo card.</p>\n","social_text":"Seeing the current U.S. administration taking an axe to DEI programs in the government and bully private businesses to do the same has me incredibly frustrated, confused, and (yes) angry. I want more equality and more opportunity in the world, not less.","url":"https://www.aaron-gustafson.com/notebook/on-diversity/","tags":["equality","inclusion","society","industry","accessibility","empathy"],"date_published":"2025-01-30T23:11:54Z"},{"id":"https://www.aaron-gustafson.com/speaking-engagements/expanding-accessibility-with-ai/","title":"📢 Expanding Accessibility with AI","summary":"This session, hosted by Aaron Gustafson and Ioana Tanase explores the transformative role of AI in enhancing accessibility. Together, you will uncover the pivotal role AI plays in crafting cutting-edge accessible technologies, learn about innovative AI tools that empower individuals with disabilities, and dive into best practices for creating inclusive AI solutions. Together, we will also explore the exciting future of AI in pushing the boundaries of accessibility.","content_html":"<p>This session, hosted by Aaron Gustafson and Ioana Tanase explores the transformative role of AI in enhancing accessibility. Together, you will uncover the pivotal role AI plays in crafting cutting-edge accessible technologies, learn about innovative AI tools that empower individuals with disabilities, and dive into best practices for creating inclusive AI solutions. Together, we will also explore the exciting future of AI in pushing the boundaries of accessibility.</p>\n<p>Learning objectives:</p>\n<ol>\n<li>Understand the pivotal role AI plays in crafting cutting-edge accessible technologies.</li>\n<li>Learn about innovative AI tools that empower individuals with disabilities.</li>\n<li>Dive into best practices for creating inclusive AI solutions.</li>\n<li>Explore the exciting future of AI in pushing the boundaries of accessibility</li>\n</ol>\n","social_text":"This session, hosted by Aaron Gustafson and Ioana Tanase explores the transformative role of AI in enhancing accessibility. Together, you will uncover the pivotal role AI plays in crafting cutting-edge accessible technologies, learn about innovative AI tools that empower individuals with disabilities, and dive into best practices for creating inclusive AI solutions. Together, we will also explore the exciting future of AI in pushing the boundaries of accessibility.","url":"","tags":["accessibility","AI/ML","inclusive design","the future","user experience","voice UX"],"image":"https://www.aaron-gustafson.com/undefined","date_published":"2024-12-11T08:08:30Z"},{"id":"https://www.aaron-gustafson.com/notebook/requirement-rules-for-checkboxes/","title":"✍🏻 Requirement Rules for Checkboxes","summary":"Currently, we can only make checkboxes required or not, individually. In some cases you need to be able to set a specific number of checkboxes that need to be checked. My <code>form-required-checkboxes</code> web component enables that.","content_html":"<p>HTML checkboxes debuted as <a href=\"https://datatracker.ietf.org/doc/html/rfc1866#section-8.1.2.3\">part of HTML 2.0 in 1995</a>. Our ability to mark an individual checkbox as being required became part of the HTML5 spec that published in 2014. A decade later, we can still only make checkboxes required on a case-by-case basis. To overcome this limitation, I had created <a href=\"https://github.com/easy-designs/easy-checkbox-required.js\">a jQuery plugin that allowed me to indicate that a user should choose a specific number of items from within a checkbox group</a>. Yesterday I turned that plugin into a web component: <a href=\"https://github.com/aarongustafson/form-required-checkboxes\"><code>form-required-checkboxes</code></a>.</p>\n<h2 id=\"markup-assumptions\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#markup-assumptions\" aria-hidden=\"true\">#</a> Markup Assumptions</h2>\n<p>Before I tuck into the details, I’ll start by saying that the web component begins with the assumption that you are following best practices with respect to form markup:</p>\n<ul>\n<li>Your checkbox group should be in a <code>fieldset</code> with a <code>legend</code></li>\n<li>All of the checkbox elements must have the same <code>name</code> (e.g., “foo[]”).</li>\n</ul>\n<p>In other words, they should look something like this:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fieldset</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>legend</span><span class=\"token punctuation\">></span></span>Group 1 label<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>legend</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>checkbox<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>foo[]<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>1<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n        First item\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>checkbox<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>foo[]<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">value</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>2<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n        Second item\n      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token comment\">&lt;!-- options continue --></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fieldset</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>To use the web component, you wrap the group in a <code>form-required-checkboxes</code> element and then include the JavaScript to initialize it.</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>form-required-checkboxes</span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fieldset</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>legend</span><span class=\"token punctuation\">></span></span>Group 1 label<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>legend</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token comment\">&lt;!-- etc. --></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fieldset</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>form-required-checkboxes</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token comment\">&lt;!-- at the end of your document --></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/web-components/form-required-checkboxes.js<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">async</span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>If you’re following right along, there’s an error waiting for you in the <code>console</code> — we need to set the requirement rules.</p>\n<h2 id=\"the-api\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#the-api\" aria-hidden=\"true\">#</a> The API</h2>\n<p>The <code>form-required-checkboxes</code> element requires at least one attribute to function, but using some of the others you can more fully customize the experience for users:</p>\n<ul>\n<li><code>required</code> - Represents the range of required values. You can set this up in one of three ways depending on your needs:\n<ul>\n<li>Single number (e.g., 3) requires exactly that number of choices.</li>\n<li>Range (e.g., 3-5) requires a minimum of the first number and a max of the second number be chosen.</li>\n<li>Max (e.g., 0-3) requires a minimum of zero and a max of the second number to be chosen.</li>\n</ul>\n</li>\n<li><code>notice</code> (optional) - This is a string description that explains details of the required value in plain language. If you don’t supply one, the component will create one for you based on the current language (if supported). This description will be added as a <code>small</code> element within the component (as a sibling to the <code>fieldset</code>).</li>\n<li><code>error</code> (optional) - This is a string validation error you’d like to be shown when the validation criteria is not met. If not provided, an appropriate error message will be generated based on the current language (if supported).</li>\n<li><code>lang</code> (optional) - Language code for localized messages (e.g., “en,” “es,” “fr,” “de”). Falls back to the nearest ancestor’s <code>lang</code> attribute or the document language.</li>\n</ul>\n<h2 id=\"localization\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#localization\" aria-hidden=\"true\">#</a> Localization</h2>\n<p>The component now includes built-in translations for 16 languages: English, Chinese (Mandarin), Hindi, Spanish, French, Arabic, Bengali, Portuguese, Russian, Japanese, German, Punjabi, Javanese, Korean, Vietnamese, and Italian. Messages are automatically generated based on the <code>lang</code> attribute.</p>\n<p>You can use it like this:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>form-required-checkboxes</span> <span class=\"token attr-name\">required</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>3<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>es<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fieldset</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>legend</span><span class=\"token punctuation\">></span></span>Opciones<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>legend</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token comment\">&lt;!-- Will display: \"Elija 3 de la lista\" --></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fieldset</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>form-required-checkboxes</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The component automatically detects the language from the <code>lang</code> attribute on the element itself, the nearest ancestor element, or the document’s <code>lang</code> attribute, falling back to English if none is found.</p>\n<p>You can also register custom translations or override existing ones using the <code>FormRequiredCheckboxesElement.registerTranslations()</code> static method. Regional language codes (e.g., <code>en-US</code>, <code>es-MX</code>) automatically fall back to their base language.</p>\n<h2 id=\"demo\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#demo\" aria-hidden=\"true\">#</a> Demo</h2>\n<p>I put together <a href=\"https://aarongustafson.github.io/form-required-checkboxes/demo/\">a comprehensive demo of the web component</a> over on GitHub:</p>\n<figure class=\"video-embed video-embed--4x3\">\n<fullscreen-control class=\"talk__slides__embed video-embed__video\">\n<iframe src=\"https://aarongustafson.github.io/form-required-checkboxes/demo/\" class=\"talk__slides__embed video-embed__video\" frameborder=\"0\"></iframe>\n</fullscreen-control>\n</figure>\n<h2 id=\"grab-it\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#grab-it\" aria-hidden=\"true\">#</a> Grab It</h2>\n<p>You can view the entire project (and suggest enhancements) over on <a href=\"https://github.com/aarongustafson/form-required-checkboxes\">the component’s Github repo</a>.</p>\n","social_text":"Currently, we can only make checkboxes required or not, individually. In some cases you need to be able to set a specific number of checkboxes that need to be checked. My `form-required-checkboxes` web component enables that.","url":"https://www.aaron-gustafson.com/notebook/requirement-rules-for-checkboxes/","tags":["accessibility","forms","HTML","JavaScript","progressive enhancement","web components","web forms"],"date_published":"2024-07-05T21:08:34Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/why-i-care-deeply-about-web-accessibility-and-you-should-too/","title":"🔗 Why I Care Deeply About Web Accessibility And You Should Too","content_html":"<p>I agree with so much of this piece… especially <a href=\"https://www.aaron-gustafson.com/speaking-engagements/delivering-critical-information-services/\">the expansive view of accessibility that is inclusive of both the disability divide and the digital divide</a>.</p>\n<p>Great summary here:</p>\n<blockquote>\n<p>[M]y passion for accessibility stems from experiencing accessibility barriers personally, observing their impact on others, and holding the conviction that technology should tear down divides - not erect new ones. I want to fulfill, and help you fulfill, the web’s promise of equal access and opportunity for everyone, regardless of circumstances. Digital accessibility should not be an accommodation but a fundamental right and prerequisite for technology to truly better humanity.</p>\n</blockquote>\n","social_text":"I agree with so much of this piece, especially the expansive view of accessibility that is inclusive of both the disability divide and the digital divide.","url":"https://www.aaron-gustafson.com/notebook/links/why-i-care-deeply-about-web-accessibility-and-you-should-too/","external_url":"https://dev.to/schalkneethling/why-i-care-deeply-about-web-accessibility-and-you-should-too-274a","tags":["accessibility","inclusive design","performance"],"date_published":"2024-05-09T17:36:18Z"}]}