Accessibility
9 Accessibility Myths and Pushbacks (And How to Answer Them)
Raising accessibility in meetings and getting pushback? You're not failing, you're just having the wrong conversations. This guide covers 9 common objections designers face, with data, reframes, and strategies to make the business case for accessibility.
ARIA Roles Explained: A Practical Guide for Web Developers
ARIA roles help assistive technologies understand the structure and purpose of HTML elements on a web page. Learn how to use ARIA roles correctly.
CSS
CSS & vertical rhythm for text, images, and tables
Vertical rhythm aligns lines to a consistent spacing cadence down the page. It creates a predictable flow for the eye to follow. Thanks to the rlh CSS unit, vertical rhythm is now easier to implement for text.
Warning: containment breach in cascade layer!
CSS cascade layers are the ultimate tool to win the specificity wars. Used alongside the :where selector, specificity problems are a thing of the past.
Or so I thought. Turns out cascade layers are leakier than a xenonite sieve. Cross-layer shenanigans can make bad CSS even badder. I discovered a whole new level of specificity hell.
The Importance of Native Randomness in CSS
Recently, I published a story about the new random functions that have landed in CSS and how they work. In this article, we’ll explore the challenges of randomness in CSS, how the concept has evolved over time, and why this native feature is a big deal.
Trimming our CSS with sibling-index() and sibling-count()
CSS got some handy new functions recently: sibling-index() and sibling-count(). sibling-index() gives us a number based on a child element’s position relative to its siblings, starting at 1. For example, the third child in a list of 10 would have an index of 3. sibling-count() gives us the total number of siblings within a parent element. We can leverage these functions for more brevity in our CSS.
Media Queries Range Syntax
Media queries are the backbone of responsive design. We use them to control how a design should change based on the viewport size. But the min-width and max-width syntax can be confusing, and in some cases, cause layout bugs that take time to spot.
This article aims to convince you to use range queries, starting today.
CSS `n of` Selectors for Conditional Validation
Sometimes we do a cursory check on user input controls before they’re all set for data validation and submission. For instance, a form might only unlock its submit button when the user has filled in a certain number of fields. Or a user needs to fill in a field in the right way to take the next step.
CSS lets you handle some of these simple checks right away, even before the browser’s validation routine runs following a submission trigger. The :valid and :invalid pseudo-classes are good examples of that. They allow browsers style fields as you type, so you can see if the data you’re entering is in the right format.
Similarly, the n of <selector-list> syntax in the :nth-child selector can also be very useful for a preliminary validation. First, let’s see what it does.
Using safe-area-inset to build mobile-safe layouts
Modern phones are not simple rectangles. They have rounded corners, camera cutouts, dynamic islands, and home indicators that double as gesture areas. Browsers know the dimensions of all of these and expose the parts that could obscure content as safe area insets.
The "safe area" is the portion of the screen that is guaranteed to be free from being obscured by system UI. The safe-area-inset is the measurement of how much space the system UI is taking up on each edge of the screen. By using these values in your CSS, you can make sure that important content and controls are not obscured by the system UI.
Safe-area-insets are baseline widely available, which means you can use them in production today and be confident that they will work for almost all your users on mobile devices.
Control the Speed of Infinite Animations
Here is a simple code that lets you adjust the speed of your infinite animation on hover (or with other interactions). It relies on animation-composition: add that allows you to run the same animation twice with an additive effect.
Vanilla Scroll Sky - A lightweight, JavaScript-free CSS utility for modern scroll-driven storytelling sections
A pure CSS scrollytelling utility for sticky image reveals and moving captions.
Vanilla Scroll Sky uses normal HTML, CSS classes, CSS Custom Properties, CSS Cascade Layers, @scope, container queries, position: sticky, and CSS scroll-driven animations.
No JavaScript. No Web Components. No framework.
Vanilla Scroll Sky targets modern browsers.
The sticky layout remains readable without scroll-driven animations. If animation-timeline: view() is not supported, images and captions are shown without transform animations.
Demo here.
Animating Focus with View Transitions
The big idea here is animating the focus ring around literally-focused elements on web pages. Like the :focus (or :focus-visible) styles, either the default or your own.
I’m just going to go ahead and say this idea I’m about to play with probably isn’t a good idea. It’s a bunch of probably-unnecessary motion. Nobody is asking for it.
Although I say that, and the WebAIM website, a site literally all about web accessibility, does it.
HTML
Reminder: You Can Stitch Together Lots of Little HTML Pages With Navigations For Interactions
I wrote about building websites with LLMs — (L)ots of (L)ittle ht(M)l page(s). I’ve tweaked a few things from that original post but the underlying idea is still the same, which I would describe as:
Avoid in-page interactions that require JavaScript in favor of multi-page navigations that rely on HTML and are enhanced with CSS view transitions (and a dash of JS if/where prudent).
Turns out, if you have a website and you think of the browser as a way to navigate documents — rather than a runtime to execute arbitrary code and fetch, compile, and present them — things can be a lot simpler than our tools often prime us to make them.
JavaScript
Introducing TanStack Form
There’s no shortage of form libraries to help manage the complexity of form handling, particularly in React. In this post, we’ll look at TanStack Form. Like other TanStack libraries, Form takes strong typing and performance seriously. It’s also detail-oriented and has planned for every imaginable edge case.
View Transitions Mock - A non-visual polyfill for Same-Document View Transitions
A spec-compliant JavaScript implementation of Same-Document View Transitions, but without the animation bits. It polyfills the full JavaScript API surface of Same-Document View Transitions.
This allows you to safely trigger Same-Document View Transitions, handle promises, and manage View Transition Types as if the browser natively supported them – ergo the mock in view-transitions-mock. The only difference with a native implementation is that you don’t get to see any visual View Transition happening.
Once registered, you can stop cluttering your codebase with if (document.startViewTransition) guards. Instead, write View Transitions code that runs anywhere — even in browsers without native support.
Formisch - The modular and type-safe form library for any framework
Formisch is a schema-based, headless form library for JS frameworks. It manages form state and validation. It is type-safe, fast by default and its bundle size is small due to its modular design. Try it out in our playground.
Supported frameworks: Preact, Qwik, React, SolidJS, Svelte and Vue.
Trustworthy JavaScript for the Open Web
Mozilla argues that while JavaScript powers the web, it’s largely untrusted and opaque, creating security and privacy risks. They call for a shift toward more transparent, auditable, and constrained JavaScript, backed by better browser protections and standards, to make the web safer and more trustworthy.
Web Application Integrity, Consistency and Transparency (WAICT) allows websites to cryptographically bind their client-side code to a manifest and commit that manifest to a publicly auditable log.
- Cryptographic binding: Ensures the JavaScript a user receives is exactly what the site intended (not tampered with in transit or by intermediaries).
- Manifest + public log: Makes deployments verifiable and auditable, so changes to code are visible and can be inspected by others.
Progressive Web Components
I’ve worked with web components for nearly a decade and built various enterprise-scale design systems with them. While I love what they offer on paper, the same pain points keep coming back:
Layout shifts, flash of unstyled content, poor server-side rendering support, too much reliance on client side JavaScript, doesn't play well with frameworks like React Server Components, accessibility issues, and so on…
Despite all of this, I still think web components are a great foundation for a design system. No other approach gives you true cross-framework portability built on what the web platform already provides. The problem isn’t necessarily the model itself, it’s how we’ve been building them.
This is how I ended up creating Elena, a library that I’m open sourcing today. Elena starts from HTML and CSS, and stays grounded in web standards and what the web platform natively provides.
Elena | Progressive Web Components
Elena is a simple, tiny library for building Progressive Web Components. Unlike most web component libraries, Elena doesn’t force JavaScript for everything. You can load HTML and CSS first, then use JavaScript to progressively add interactivity
The HTML Sanitizer API
The web platform now includes new APIs that make parsing and sanitizing HTML much safer. The spec introduces safer ways to insert HTML into the DOM, beyond the old innerHTML approach.
The API gives us six methods, split into two families:
- Safe methods:
Element.setHTML(),ShadowRoot.setHTML(),Document.parseHTML(). These always strip XSS-unsafe content, no matter what configuration you pass. - Unsafe methods:
Element.setHTMLUnsafe(),ShadowRoot.setHTMLUnsafe(),Document.parseHTMLUnsafe(). These do exactly what you tell them to, including allowing dangerous content if your config says so.