Accessibility
Can AI Agent Skills Help Developers Ship Accessible Code?
This is part one of a multi-part series on using AI agent skills to improve accessibility in code. Part two will put the Intopia Web Accessibility Skill to the test with real development challenges across Claude and Cursor.
Your skip link targets may not need tabindex=-1 to work properly
Recently, someone posted on LinkedIn that skip links are often broken because their target elements are missing a tabindex attribute. I was really surprised to see that because I thought that was an issue of the past. That's why I decided to test it.
Eight quick things to remember when using aria-owns
Here are eight quick things to remember when using the aria-owns attribute.
This article looks at aria-owns from both a specification perspective and a practical, real-world perspective.
Accessibility overlays create problematic ‘quick-fixes’
Accessibility isn’t something you can layer on top of a broken foundation. Without fixing the foundation, overlays create disruption for some users, but fail to offer legal protection.
A11y 101: 2.5.8 Target Size
Here’s a scenario I see all the time. A designer hands me a mockup with these elegant, tiny icons in a row; maybe a toolbar with edit, delete, and share buttons, each one maybe 16 pixels square. Looks clean. Minimal. Modern.
Then I put my thumb on it. And I miss. Every. Single. Time. Small targets, big problems.
That’s the friction WCAG 2.5.8: Target Size (Minimum) is trying to smooth out.
Making emojis and icons screen reader accessible
While emojis and icons often look like images to visual users, they often aren’t real images in the code. This means there are specific strategies and considerations for making emojis and icons accessible to assistive technology users.
In this article, we’re focusing on ways you can make sure your emojis and icons are accessible with screen readers.
CSS
Looking at New CSS Multi-Column Layout Wrapping Features
Multi-column layouts have not been used to their full potential, mostly because once content exceeded a limit, multi-column would force a horizontal scroll. It’s unintuitive and a UX no-no, especially on the modern web where the default scroll is vertical.
Chrome 145 introduces the column-height and column-wrap properties, enabling us to wrap the additional content into a new row below, creating a vertical scroll instead of a horizontal scroll.
Alternatives to the !important Keyword
Every now and then, I stumble onto an old project of mine, or worse, someone else’s, and I’m reminded just how chaotic CSS can get over time. In most of these cases, the !important keyword seems to be involved in one way or another. And it’s easy to understand why developers rely on it. It provides an immediate fix and forces a rule to take precedence in the cascade.
That’s not to say !important doesn’t have its place. The problem is that once you start using it, you’re no longer working with the cascade; you’re bypassing it. This can quickly get out of hand in larger projects with multiple people working on them, where each new override makes the next one harder.
Cascade layers, specificity tricks, smarter ordering, and even some clever selector hacks can often replace !important with something cleaner, more predictable, and far less embarrassing to explain to your future self.
Let's Reshape the Web using border-shape
To create CSS Shapes, I mainly rely on clipping (using clip-path) or masking (using mask). Both are very powerful and can be used to create all the possible shapes. However, they are limited if we want to add decorations such as borders and shadows.
The corner-shape property is a good alternative that allows us to create CSS shapes with decorations. However, since it's only about shaping the corners, it remains limited to a subset of shapes.
Another alternative is the new and powerful border-shape.
Introducing view-transitions-toolkit, a collection of utility functions to more easily work with View Transitions
In my work with View Transitions over the last several years, I’ve published everything from deep-dive articles, demos, and announcement videos at Google I/O. I’ve also done some more experimental things with it, such as optimizing the keyframes or driving a View Transition by scroll.
To turn the lessons from these scattered experiments into something more reusable for both you and me, I’ve bundled the most frequent code patterns into a dedicated package: view-transitions-toolkit.
You can find some demos here.
Bearnie - Build your own component library
Accessible components for Astro and Tailwind CSS. Components are added to your project with the CLI. You own and control the code. Built specifically for Astro. No React, Vue, or Svelte required.
This is not an Astro component library. It's how you build your Astro component library.
HTML
When All You Can Do Is All or Nothing, Do Nothing
I’ve been working a lot over the last few years on the idea of web performance for design systems. While a lot of my clients want me to start at the end and work back ("we have a slow site, how can we make it faster?"), particularly ambitious clients ask "how can we bake web performance in from the start?" This post comes from a specific bit of advice I gave a client recently.
And so my take is this: when all you can do is all or nothing, do nothing.
Semantic HTML Just Might Make Your CSS Less Fragile
A real-world exploration of how choosing the right HTML elements for interview transcripts solves both semantic and styling challenges in one cascading swoop.
How To Use Standard HTML Video & Audio Lazy-Loading on the Web Today
HTML video and audio lazy loading is now a web standard and quickly gaining support in all major browsers. This feature was long overdue and, particularly given Squarespace’s role in proposing and implementing it, we’re very excited to see how developers use it on the web.
In this post, we’ll cover some best practices for using video and audio lazy loading in any website, as well as some gotchas to avoid. Let’s dive into how we can make use of audio and video lazy loading in websites today.
JavaScript
Zumly - Zoom-based navigation for the web
Zumly is a JavaScript library for hierarchical zoom navigation: you move in Z (depth) through discrete views laid out in the XY plane, with spatial transitions instead of flat screen swaps. It is inspired by zoomable user interfaces (ZUI) but targets structured, trigger-driven zoom—not infinite pan/zoom canvases.
You can't cancel a JavaScript promise (except sometimes you can)
You can't cancel a JavaScript promise. There's no .cancel() method, no AbortController integration, no built-in way to say "never mind, stop." The TC39 committee considered adding cancellation in 2016, but the proposal was withdrawn after heated debate. Part of the problem is that cancelling arbitrary code mid-execution can leave resources in a dirty state (open handles, half-written data), so true cancellation requires cooperative cleanup, which undermines the simplicity people want from a .cancel() method.
But you can do something weirder: return a promise that never resolves, await it, and let the garbage collector clean up the suspended function. No exceptions, no try/catch, no special return values. The function just stops.
RSC Boundary - Tooling to visualize React Server Components vs Client Components boundaries in Next.js App Router
See where Server Components end and Client Components begin—directly in the browser, on your real app.
RSC Boundary is a lightweight devtool for Next.js App Router apps. Add one provider to your root layout and you get outlines, labels, and a panel that map server-rendered regions vs client subtrees—no annotations on every file, no guessing from the file tree alone.
What To Know in JavaScript (2026 Edition)
We’ll cover new stuff in the language itself, but being a JavaScript practitioner involves more than the language itself, extending into runtimes, frameworks, libraries, and tooling.
React Direct to Canvas
A proof-of-concept that intercepts React's DOM writes and redirects them to a canvas — without a custom renderer. Built with React 19, Yoga Layout, Vite, and TypeScript.
This technique leverages a Fake DOM as a secondary virtual DOM, by directing React to render UI onto it, and then re-constructing the UI directly onto canvas. The result is a trade-off.
What you lose:
- Accessibility features
- Native reflow, layout, and styling via CSS
- Incremental paint by the browser
What you gain:
- Pixel-perfect control
- Advanced graphics
- High performance rendering
- ...all within the familiar React API!
The dream is to build UI-intensive applications like Figma using React without the usual performance caps.
phantom-ui - Structure-aware skeleton loader. One Web Component, every framework
Stop building skeleton screens by hand. Wrap your real UI in <phantom-ui> and it generates shimmer placeholders automatically by measuring your actual DOM at runtime.
No separate skeleton components to maintain. No copy-pasting layouts. The real component is the skeleton template.
AbortController Beyond Fetch: Timeouts, Cleanup, and Signal Composition
AbortController is a general-purpose JavaScript cancellation primitive that works with timeouts, event listeners, streams, concurrent operations, and graceful shutdowns. It's been in every browser with JavaScript (97% support) and Node.js since v15. Let's go over how you can use it beyond cancel.
crashcat - a physics engine for javascript, built for games, simulations, and creative websites
Features
- rigid body simulation
- support for convex shapes, triangle mesh shapes, custom shapes
- constraints with motors and springs (hinge, slider, distance, point, fixed, cone, swing-twist, six-dof)
- continuous collision detection (ccd) for fast-moving objects
- flexible collision filtering
- hooks for listening to and modifying physics events
- broadphase spatial acceleration with dynamic bvh
- rigid body sleeping
- sensor rigid bodies
- pure javascript, written to be highly tree-shakeable, only pay for what you use
- works with any javascript engine/library - babylon.js, playcanvas, three.js, or your own engine
SSGOI - animated page transition for major ssr frameworks and browsers, including Safari
Smooth page transitions. Works on all browsers and supports all frameworks. Start with just a few lines of code without complex setup.
You can add animations while using your framework's routing as-is. Compatible with all routing approaches including Next.js Link, SvelteKit's goto, Vue Router, and more.
Demo here.
boneyard - Auto generated skeleton loading framework
Pixel-perfect skeleton loading screens, extracted from your real UI. No manual measurement, no hand-tuned placeholders.
Works with React, Vue, Svelte 5, Angular, and React Native.
The Intl API: The best browser API you're not using
Chances are you've used Moment.js, date-fns, Luxon, or numeral.js at some point. Developers have relied on these libraries for years to format dates, numbers, and currencies. Those are all very useful libraries, but they also come with a cost: they add kilobytes to your download size and they require client-side code parsing.
The Intl API is baseline widely available (except for Intl.DurationFormat. It works in all current evergreen browsers, but hasn't been around long enough to qualify for "widely available".) and can handle almost all of your formatting requirements directly in the browser, with zero kB of download and no JS bundle parsing required. It also knows your users' locale preferences so you can format dates and numbers in a way that feels natural to them without any extra work.