https://nolanlawson.com/2025/06/16/selfish-reasons-for-building-accessible-uis/ Read the Tea Leaves Software and other dark arts, by Nolan Lawson [Search this Blog ] Search * Home * Apps * Code * Talks * About << AI ambivalence 16 Jun Selfish reasons for building accessible UIs Posted June 16, 2025 by Nolan Lawson in accessibility, Web. Tagged: accessibility. 4 Comments All web developers know, at some level, that accessibility is important. But when push comes to shove, it can be hard to prioritize it above a bazillion other concerns when you're trying to center a
and you're on a tight deadline. A lot of accessibility advocates lead with the moral argument: for example, that disabled people should have just as much access to the internet as any other person, and that it's a blight on our whole industry that we continually fail to make it happen. I personally find these arguments persuasive. But experience has also taught me that "eat your vegetables" is one of the least effective arguments in the world. Scolding people might get them to agree with you in public, or even in principle, but it's unlikely to change their behavior once no one's watching. So in this post, I would like to list some of my personal, completely selfish reasons for building accessible UIs. No finger-wagging here: just good old hardheaded self-interest! Debuggability When I'm trying to debug a web app, it's hard to orient myself in the DevTools if the entire UI is "div soup":
Library
Version
Size
UI
React
19.1.0
167kB
Style
Tailwind
4.0.0
358kB
Build
Vite
6.3.5
2.65MB
This is actually a table, but you wouldn't know it from looking at the HTML: Screenshot of an HTML table with column headers library, version, and size, row headers UI, style, and build, and values React/Tailwind/ Vite with their version numbers and build size in the cells. If I'm trying to debug this in the DevTools, I'm completely lost. Where are the rows? Where are the columns?
Library Version Size
UI React 19.1.0 167kB
Style Tailwind 4.0.0 358kB
Build Vite 6.3.5 2.65MB
Ah, that's much better! Now I can easily zero in on a table cell, or a column header, because they're all named. I'm not wading through a sea of
s anymore. Even just adding ARIA roles to the
s would be an improvement here:
Library
Version
Size
UI
React
19.1.0
167kB
Style
Tailwind
4.0.0
358kB
Build
Vite
6.3.5
2.65MB
Especially if you're using a CSS-in-JS framework (which I've simulated with robo-classes above), the HTML can get quite messy. Building accessibly makes it a lot easier to understand at a distance what each element is supposed to do. Naming things As all programmers know, naming things is hard. UIs are no exception: is this an "autocomplete"? Or a "dropdown"? Or a "picker"? Screenshot of a combobox with "Ne" typed into it and states below in a list like Nebraska, Nevada, and New Hampshire. If you read the WAI ARIA guidelines, though, then it's clear what it is: a "combobox"! No need to grope for the right name: if you add the proper roles, then everything is already named for you: * combobox * listbox * options As a bonus, you can use aria-* attributes or roles as a CSS selector. I often see awkward code like this:
The active class is clearly redundant here. If you want to style based on the .active selector, you could just as easily style with [aria-selected="true"] instead. Also, why call it isActive when the ARIA attribute is aria-selected? Just call it "selected" everywhere:
Much cleaner! I also find that thinking in terms of roles and ARIA attributes sharpens my thinking, and gives structure to the interface I'm trying to create. Suddenly, I have a language for what I'm building, which can lead to more "obvious" variable names, CSS custom properties, grid area names, etc. Testability I've written about this before, but building accessibly also helps with writing tests. Rather than trying to select an element based on arbitrary classes or attributes, you can write more elegant code like this (e.g. with Playwright): await page.getByLabel('Name').fill('Nolan') await page.getByRole('button', { name: 'OK' }).click() Imagine, though, if your entire UI is full of
s and robo-classes. How would you find the right inputs and buttons? You could select based on the robo-classes, or by searching for text inside or nearby the elements, but this makes your tests brittle. As Kent C. Dodds has argued, writing UI tests based on semantics makes your tests more resilient to change. That's because a UI's semantic structure (i.e. the accessibility tree) tends to change less frequently than its classes, attributes, or even the composition of its HTML elements. (How many times have you added a wrapper
only to break your UI tests?) Power users When I'm on a desktop, I tend to be a keyboard power user. I like pressing Esc to close dialogs, Enter to submit a form, or even / in Firefox to quickly jump to links on the page. I do use a mouse, but I just prefer the keyboard since it's faster. So I find it jarring when a website breaks keyboard accessibility - Esc doesn't dismiss a dialog, Enter doesn't submit a form, |/| don't change radio buttons. It disrupts my flow when I unexpectedly have to reach for my mouse. (Plus it's a Van Halen brown M&M that signals to me that the website probably messed something else up, too!) If you're building a productivity tool with its own set of keyboard shortcuts (think Slack or GMail), then it's even more important to get this right. You can't add a lot of sophisticated keyboard controls if the basic Tab and focus logic doesn't work correctly. A lot of programmers are themselves power users, so I find this argument pretty persuasive. Build a UI that you yourself would like to use! Conclusion The reason that I, personally, care about accessibility is probably different from most people's. I have a family member who is blind, and I've known many blind or low-vision people in my career. I've heard firsthand how frustrating it can be to use interfaces that aren't built accessibly. Honestly, if I were disabled, I would probably think to myself, "computer programmers must not care about me." And judging from the miserable WebAIM results, I'd clearly be right: Across the one million home pages, 50,960,288 distinct accessibility errors were detected--an average of 51 errors per page. As a web developer who has dabbled in accessibility, though, I find this situation tragic. It's not really that hard to build accessible interfaces. And I'm not talking about "ideal" or "optimized" - the bar is pretty low, so I'm just talking about something that works at all for people with a disability. Maybe in the future, accessible interfaces won't require so much manual intervention from developers. Maybe AI tooling (on either the production or consumption side) will make UIs that are usable out-of-the-box for people with disabilities. I'm actually sympathetic to the Jakob Nielsen argument that "accessibility has failed" - it's hard to look at the WebAIM results and come to any other conclusion. Maybe the "eat your vegetables" era of accessibility has failed, and it's time to try new tactics. That's why I wrote this post, though. You can build accessibly without having a bleeding heart. And for the time being, unless generative AI swoops in like a deus ex machina to save us, it's our responsibility as interface designers to do so. At the same time we're helping others, though, we can also help ourselves. Like a good hot sauce on your Brussels sprouts, eating your vegetables doesn't always have to be a chore. Related 4 responses to this post. 1. James Morrin's avatar Posted by James Morrin on June 16, 2025 at 11:48 AM The testing use cases are huge! I remember long ago I worked at a company that used "data-test-*" in their markup. It always felt wrong to me, but I didnt have a good alternative to propose. Normally if I can't propose a better alternative solution I dont think I have a right to complain so I never said anything. Well now I have a solution going forward! NICE! Reply + Nolan Lawson's avatar Posted by Nolan Lawson on June 16, 2025 at 1:28 PM Yep, to me data-testid is a last resort. It is necessary sometimes if you're testing something non-semantic (e.g. "ensure the animation on this bit of the UI looks right"), but most of the time it's not needed. Reply 2. Jon's avatar Posted by Jon on June 17, 2025 at 12:26 AM The escape key exits fullscreen mode on my computer, so accessibility evangelists have to contend with that kind of thing too. Reply 3. Dhruv Joshi's avatar Posted by Dhruv Joshi on June 17, 2025 at 2:11 AM I strongly agree with your point. In the early days, external CSS frameworks have influenced these
oriented structure, which can be avoided by properly following the HTML schematics. Instead, use purpose built tags provided by the HTML first, then think about styling them by either using your preferred CSS framework or even going partially/fully class-less. I have tried the fully class-less theme approach recently while migrating my old blog site and that experience pushed me to explore the accessibility attributes discussed here. Reply Leave a comment Cancel reply [ ] [ ] [ ] [ ] [ ] [ ] [ ] D[ ] This site uses Akismet to reduce spam. Learn how your comment data is processed. Recent Posts * Selfish reasons for building accessible UIs * AI ambivalence * Goodbye Salesforce, hello Socket * 2024 book review * Avoiding unnecessary cleanup work in disconnectedCallback About Me Photo of Nolan Lawson, headshot I'm Nolan, a programmer from Seattle working at Socket. All opinions are my own. Photo by Catalin Maris. Archives * June 2025 (1) * April 2025 (1) * January 2025 (1) * December 2024 (2) * October 2024 (2) * September 2024 (3) * August 2024 (1) * July 2024 (1) * March 2024 (1) * January 2024 (1) * December 2023 (4) * August 2023 (2) * January 2023 (2) * December 2022 (1) * November 2022 (2) * October 2022 (2) * June 2022 (4) * May 2022 (3) * April 2022 (1) * February 2022 (1) * January 2022 (1) * December 2021 (3) * September 2021 (1) * August 2021 (6) * February 2021 (2) * January 2021 (2) * December 2020 (1) * July 2020 (1) * June 2020 (1) * May 2020 (2) * February 2020 (1) * December 2019 (1) * November 2019 (1) * September 2019 (1) * August 2019 (2) * June 2019 (4) * May 2019 (3) * February 2019 (2) * January 2019 (1) * November 2018 (1) * September 2018 (5) * August 2018 (1) * May 2018 (1) * April 2018 (1) * March 2018 (1) * January 2018 (1) * December 2017 (1) * November 2017 (2) * October 2017 (1) * August 2017 (1) * May 2017 (1) * March 2017 (1) * January 2017 (1) * October 2016 (1) * August 2016 (1) * June 2016 (1) * April 2016 (1) * February 2016 (2) * December 2015 (1) * October 2015 (1) * September 2015 (1) * July 2015 (1) * June 2015 (2) * October 2014 (1) * September 2014 (1) * April 2014 (1) * March 2014 (1) * December 2013 (2) * November 2013 (3) * August 2013 (1) * May 2013 (3) * January 2013 (1) * December 2012 (1) * November 2012 (1) * October 2012 (1) * September 2012 (3) * June 2012 (2) * March 2012 (3) * February 2012 (1) * January 2012 (1) * November 2011 (1) * August 2011 (1) * July 2011 (1) * June 2011 (3) * May 2011 (2) * April 2011 (4) * March 2011 (1) Tags accessibility alogcat android android market apple app tracker benchmarking blobs boost bootstrap browsers bug reports catlog chord reader code contacts continuous integration copyright couch apps couchdb couchdroid developers development emoji grails html5 indexeddb information retrieval japanese name converter javascript jenkins keepscore listview logcat logviewer lucene nginx nlp node nodejs npm offline-first open source passwords performance pinafore pokedroid pouchdb pouchdroid query expansion relatedness calculator relatedness coefficient s3 safari satire sectioned listview security semver shadow dom social media socket.io software development solr spas supersaiyanscrollview synonyms twitter ui design ultimate crossword w3c webapp webapps web platform web sockets websql Links * Mastodon * GitHub * npm Blog at WordPress.com. * Comment * Reblog * Subscribe Subscribed + [favico] Read the Tea Leaves Join 1,280 other subscribers [ ] Sign me up + Already have a WordPress.com account? Log in now. * Privacy * + [favico] Read the Tea Leaves + Subscribe Subscribed + Sign up + Log in + Copy shortlink + Report this content + View post in Reader + Manage subscriptions + Collapse this bar Loading Comments... Write a Comment... [ ] Email (Required) [ ] Name (Required) [ ] Website [ ] [Post Comment] [b]