Accessibility
Automated Accessibility Testing for React - Tools and Best Practices you can use
In this article I'm going to explain what tools, scripts, frameworks, services and libraries that I (and you) can use to automate these accessibility checks, and how to get them in your CI/CD deployment pipeline.
Can you make toast messages accessible?
Toast notifications are fundamentally inaccessible and should be abandoned rather than improved. Here's why.
IDREFs: What they are and how to use them
Using explicit IDREFs (instead of relying on nesting) helps ensure consistent behavior across browsers and assistive technologies — making forms and interactive components more reliably accessible.
Since many ARIA attributes depend on IDREFs to describe relationships and structure for screen readers, proper IDREF usage supports better accessibility compliance and more inclusive web experiences.
Accessible by Design: The Role of the 'lang' Attribute
When starting a project, whether it is an application, a mobile app or site, or just a website in general I still see an alarming number of examples where the language attribute is not included in the <html> element.
I am here to discuss the importance of the language attribute in your code.
Dealbreaker bugs in native popovers
One of my clients decided to write a custom popover component that uses native popovers under the hood. We built the component and were happy with it. They were about to ship it until we realised there was an accessibility bug so severe that it was a dealbreaker for us.
Popovers are floating UI elements you can show or hide by pressing a button. They come with many accessibility features built in, so you don’t have to handle most of the work. You can learn more about that in “The accessibility of the popover attribute”.
Did you know your browser has two accessibility trees?
This article traces the full lifecycle of an accessibility event. From the moment the DOM changes, through Blink’s internal systems, through its internal accessibility tree, and finally back out into the BrowserAccessibility tree that screen readers query.
This is a highly technical look at how Chrome actually works.
How We Automate Accessibility Testing with Playwright and Axe
Automating accessibility testing with Playwright and Axe doesn’t find every a11y problem, but it gives us a baseline that runs on every PR and helps us catch the obvious issues before they ever reach production.
We had high hopes for catching complex navigation issues, but the reality is that automated tests are best at finding basic problems.
What our tests do catch:
- Missing alternative text for images (alt attributes)
- Color contrast problems
- Semantic HTML errors (e.g., improper heading structure)
What our tests don't catch:
- Complex keyboard navigability issues
- Clarity or comprehensibility of content
These more complex issues still require manual testing and review by accessibility experts (for now).
CSS
<dialog> and popover: Baseline layered UI patterns
The <dialog> element and the popover attribute are two Baseline layered UI patterns that developers can reach for instead of custom implementations. To show the advantages of using layered UI patterns built into today's web browsers—and to give an example of when you might reach for <dialog> or use the popover attribute—this article walks through an example of a modal that appears when the user attempts to save an image to a favorites list without being logged in.
Using CSS custom functions
CSS custom functions enable you to create reusable blocks of CSS code that can accept arguments, contain complex logic (defined using features such as CSS if() functions and @media at-rules), and return values based on that logic. They work similarly to CSS custom properties, but provide more flexibility.
In this article, we'll show you how to use them and present some real-world examples.
How To Create an Adaptive SVG Favicon Using the prefers-color-scheme Media Query
Find out how to create an adaptive favicon that automatically switches to a light/dark color scheme using SVG icon format and prefers-color-scheme media query.
Scrollytelling on Steroids With Scroll-State Queries
Unconvinced of the value of scrollytelling? Alright, skeptic, let’s first warm up with some common use cases for scroll-based styling.
CSS Wrapped 2025
Ready to see what we molded in 2025? The Chrome DevRel team will guide you through 17 CSS and UI features that landed on the Web Platform.
The Deep Card Conundrum
Imagine a card that isn’t just a 2D plane, but a container with actual volume. A card that holds a miniature 3D world inside it. When you rotate this card, you don’t just see it skew, you see the elements inside it shift in perspective, revealing their depth. It’s like holding a glass box filled with floating objects.
A pragmatic guide to modern CSS colours - part two
In my previous article on colours, I dove into the practical side of the new colour features for developers who primarily copy and paste values from a design file into their editor.
With all the new colour features that we have in CSS now, we can do more with colours in the browser than designers can do in their design apps, and it opens up a whole world of possibilities.
Why are my view transitions blinking?
When you call document.startViewTransition(), the browser creates pseudo-elements (::view-transition-old() and ::view-transition-new()) that represent the before and after states of your content. The browser then animates between these snapshots, creating smooth visual transitions. You can read more on that here.
I spent more time than I’d like to admit debugging view transitions blinks before understanding what was happening. The API seemed straightforward enough, but my transitions kept flashing. Here’s what I learned, so you don’t have to repeat my mistakes.
Creating Scroll-Based Animations in Full view()
The CSS animation-timeline property accepts a view() function which, in turn, returns a timeline of how much of an element is visible in the part of a scroll container that’s viewable (formally known as a scrollport). In other words, rather than letting an animation run a linear progression based on how much time has elapsed, view() runs animations based on the visibility of the animated element within a scrollport.
I like to equate it as the CSS version of JavaScript’s Intersection Observer. We can run an animation on an element as that element enters and exits the scrollport.
HTML
Controlling dialogs and popovers with the Invoker Commands API
The Invoker Commands API adds new attributes to the <button> element to control interactive elements on the page such as popovers and modal dialogs without having to write JavaScript.
Until now, users wanting to implement the <dialog> element needed to write their own JavaScript to power the show and hide functionality using the HTMLDialogElement interface, while the Popover API and Invoker Commands API for popovers work identically by using HTMLElement attributes to show, hide, or toggle the popover.
Why should you use this new API, and what benefits does it bring?
JavaScript
Drone-ambient-noise synthesizer in Javascript: when instability is a feature, not a bug
We will talk about the nuances of using the Web Audio API and Web MIDI API for sound synthesis in the browser, the methods of databending and sonification, the UX when using the keyboard and mouse for musical purposes, and why the ungoogled-chromium browser is better than Google Chrome.
comlink: Comlink makes WebWorkers enjoyable
Comlink is a tiny library (1.1kB), that removes the mental barrier of thinking about postMessage and hides the fact that you are working with workers.
At a more abstract level it is an RPC implementation for postMessage and ES6 Proxies.
On mobile phones, and especially on low-end mobile phones, it is important to keep the main thread as idle as possible so it can respond to user interactions quickly and provide a jank-free experience. The UI thread ought to be for UI work only. WebWorkers are a web API that allow you to run code in a separate thread. To communicate with another thread, WebWorkers offer the postMessage API. You can send JavaScript objects as messages using myWorker.postMessage(someObject), triggering a message event inside the worker.
Newton's Cradle Tutorial
Walks you through how to build a simple, interactive version of Newton's Cradle in JavaScript. The demo uses a canvas to draw 5 swinging balls and simulates pendulum physics, collision, and momentum transfer — letting you click or drag balls to start a “swing.”
2Dphysics
The World's smallest 2D physics engine in JavaScript including springs and joints.
GitHub repo here.
Angular pipes: Time to rethink
Angular’s toolkit provides developers with just a few core primitives to solve a wide range of tasks. In my previous articles, we’ve already explored a fundamental concept — Directives, and tried to articulate the core idea behind it.
This time, we’ll take a closer look at Pipes, whose role in Angular is becoming a subject of reconsideration with the introduction of the new reactivity system.
SweetAlert++ - Beautiful, accessible modals, toasts, and forms with premium effects
A modern, accessible, lightweight modal and alert library. The better alternative to SweetAlert2.
- Lightweight: Core is ~5KB gzipped, full library ~12KB (vs SweetAlert2's ~15KB)
- Tree-shakeable: Import only what you need
- Accessible: Full WCAG 2.1 AA compliance, proper focus management, screen reader support
- Modern: CSS custom properties, Web Animations API, ESM-first
- Framework Ready: First-class React and Vue 3 adapters
- TypeScript: Complete type definitions
- No Dependencies: Zero runtime dependencies
- SSR Safe: Works with Next.js, Nuxt, and other SSR frameworks
- Dark Mode: Automatic dark mode support via CSS custom properties
- Reduced Motion: Respects
prefers-reduced-motion
GitHub repo here.
UX
Designing Effective Contextual Menus: 10 Guidelines
Contextual menus reduce clutter and interaction cost but have low information scent. Prioritize clarity, consistency, and proximity to balance the tradeoffs.
Miscellaneous
ENV Variable Naming Conventions & Best Practices
A concise guide to consistent, portable, collision-free environment variable naming that works across languages and teams.
Animating SVGs with LLMs
I started exploring how to build custom loading animations with LLMs. Not Sora generating 6MB videos, but animated SVGs that are only a few KB, render instantly, and are pixel perfect vector graphics. I've landed on a system that works pretty well.
Useful patterns for building HTML tools
I’ve started using the term HTML tools to refer to HTML applications that I’ve been building which combine HTML, JavaScript, and CSS in a single file and use them to provide useful functionality. I have built over 150 of these in the past year, almost all of them written by LLMs. This article presents a collection of useful patterns I’ve discovered along the way.
console-text - Get Error Alerts Instantly via SMS Delivery
Sign up instantly - no credit card required.
SMS Delivery: Alerts are sent to the phone number you provide during signup. Make sure it's a number you can access.
Rate Limits: 10 identical messages per minute, 50 total messages per account
Free Forever: No credit card required. Start alerting in 30 seconds with your free account.
This is for solo devs and side projects who want dead-simple alerts without the setup overhead. If you know console.log(), you already know how to use it.