Skip to main content
Bartek Czyż
← writing
12 min read
  • accessibility
  • w3c

Accessibility is not about them. It's about you, next Tuesday

by Bartek

Accessibility is not about them. It's about you, next Tuesday
Photo by Aidan De La Paz on Unsplash

There's a moment I think about a lot.

You're standing at a parking meter that has, mercifully, been replaced by an app. It's July, the sun is directly overhead, and your phone screen has become a small mirror of the sky. You can see your own squinting face perfectly. The app's UI - that elegant light-grey-on-white design the team was so proud of in Figma - is invisible. You tilt the phone. You cup your hand over it. You walk three steps to find shade behind a tree. Somewhere, a parking inspector is approaching.

Here's what I want you to notice: in that moment, you have a disability. A temporary, situational, entirely ordinary one. Your eyes work fine. The phone works fine. The app "works." But the system of you-plus-phone-plus-sunlight does not work, and the reason it doesn't work is that somebody - a designer, a developer, a product manager, probably all three - decided that 3:1 contrast was "elegant" and shipped it.

We've spent twenty years talking about accessibility as if it were a charity project for someone else. A niche. A compliance checkbox. A thing you add at the end if the deadline permits. And that framing is not just wrong - it is the single biggest reason most software is quietly, stupidly hostile to its own users.

Let me try to convince you of something better.

The spectrum nobody told you about

In 2016, Microsoft's Inclusive Design team published a little diagram that should be taped to the monitor of every product person on earth. They call it the Persona Spectrum, and it looks something like this:

AbilityPermanentTemporarySituational
TouchOne armArm injuryNew parent holding a baby
SeeBlindCataractBright sunlight on a screen
HearDeafEar infectionNoisy bar, sleeping partner
SpeakNon-verbalLaryngitisHeavy accent, second language

The point of the grid is simple and a little devastating: the same human limitation shows up in three flavors. Someone somewhere has it forever. Someone has it for six weeks with a cast on their wrist. And any of us, on any given Tuesday, will have it for the next ninety seconds.

Microsoft ran the numbers on just one row - the touch row. In the US alone: roughly 26,000 people with one arm, about 13 million with a temporary arm injury, and around 8 million holding a baby, a coffee, or a grocery bag at any given moment. Solve for the 26,000 and you've accidentally helped 21 million. That isn't charity. That is leverage.

A note, because the disability community is rightly careful about this: a sleeping baby is not a disability in the way blindness is a disability. The W3C prefers the phrase "situational limitations" for exactly this reason, and I think they're right. What I'm arguing is not that a bright afternoon is the same as blindness. I'm arguing that the design response is often identical, and the benefit ripples far beyond the people who need it most.

Scenes from a normal week

You know the parking app. Here are a few more.

Tuesday, 8:14 a.m., Tram Line 2. One hand on the overhead rail because the driver brakes like he's personally offended by inertia. The other hand holding your phone. You need to validate a tram ticket in the next ninety seconds, but the "Buy" button is tucked into the top-right corner of the screen - a zone your thumb cannot physically reach without a second hand you don't have. Steven Hoober's observational study of smartphone users found that 75% of mobile interactions are thumb-driven and about half of us use our phones one-handed, constantly. The "top-right primary action" is, and always has been, hostile architecture.

Wednesday, 11:47 p.m. Your partner is asleep beside you. Volume is at zero. The tutorial video you need to watch has no captions and no transcript. You close the tab. A Preply survey last year found 70% of Gen Z Americans watch everything with subtitles on - not because they're deaf, but because audio mixing is terrible, accents vary, and real life happens in quiet apartments and loud airports. Captions are the curb cut of the streaming era.

Thursday, 7:20 a.m. You've got a cast on your dominant hand from slipping on ice last week. The expense-report tool at work won't let you Tab between form fields because every input is a custom <div> with an onclick handler. You are hunting-and-pecking through twenty-eight fields with one hand, and you are not having a good morning.

Friday, minus 8°C, ski resort. Gloves on. The lift-ticket kiosk has a "Pay" button the size of a postage stamp. Taking the gloves off means ten seconds of exposure and forty minutes of frozen fingers. You take the gloves off.

Sunday, 3:00 a.m., nursery. The baby finally asleep on your left arm. One-handed, in the dark, you are trying to mute an autoplay video before the notification ping wakes her up. If it does, everything is lost. Every single thing.

None of these people are disabled. All of these people are, in that moment, exactly as locked-out as someone with a permanent disability who was never designed for. The difference is only in duration.

And then there's the thing nobody wants to mention

We are all, statistically, going to get old.

The WHO's ageing fact sheet puts it plainly: by 2030, one in six people on earth will be 60 or older - 1.4 billion people. By 2050, it's 2.1 billion, and the over-80 population triples to 426 million. Presbyopia - the gradual stiffening of your eye lenses that makes small text impossible - arrives for most people in their mid-forties. Disabling hearing loss hits one in four people over 60 today. My own father, who built his career on spreadsheets, now opens every document and immediately zooms to 150%.

The 11-pixel grey text you shipped last sprint because it "looked clean" is text you, personally, will not be able to read in fifteen years. Neither will the person who signed off the design review. You are building your own future friction.

Why we keep not doing it

Here's the part I find hardest to defend as a developer, because I've been guilty of most of it.

Accessibility is usually skipped not out of malice but out of position in the workflow. It gets shoved to the end of the project, after everything important has been built on top of foundations that quietly exclude people. Retrofitting labels onto a form of custom <div>s takes hours. Writing <label for="email"> took three seconds.

The WebAIM Million report scans the top one million homepages on the web every year. The 2025 edition found that 94.8% of them had detectable WCAG failures, averaging 51 errors per page. And 96% of those errors fall into just six categories that have been the same six categories for five straight years: low contrast, missing alt text, missing form labels, empty links, empty buttons, and missing <html lang>.

These are not hard problems. These are embarrassing problems. They persist because nobody on the team sees them - designers because Figma doesn't show focus order or screen-reader flow, developers because their framework defaults don't trip any obvious errors, PMs because the user stories in Jira never said "and also, a blind person should be able to use this." Nobody is against accessibility. We've just built workflows in which it is invisible.

The embarrassingly short to-do list

Here is roughly 80% of what most teams are missing, in the time it takes to drink a coffee.

Use the HTML element that already does the thing. A real <button> is keyboard-focusable, announces itself to screen readers, fires on Space and Enter, and has a cursor. A <div> with an onclick is none of those things and costs you a dozen lines of code to half-fake.

html
<!-- Hostile. Keyboard users can't reach it. Screen readers don't see it. -->
<div class="btn" onclick="submit()">Pay now</div>

<!-- Humane. Accessible by default. Works in the sun and in the rain. -->
<button type="submit">Pay now</button>

Write real <label>s, not placeholder text. Placeholders vanish the moment you start typing, taking the question with them. Labels don't.

html
<!-- Once they start typing, they've forgotten what the field was for. -->
<input type="email" placeholder="Email address" />

<!-- Persistent. Clickable. Screen-reader-friendly. Twice as long. Worth it. -->
<label for="email">Email address</label>
<input id="email" type="email" />

Check your contrast. 4.5:1 for body text, 3:1 for large text. That's the WCAG AA bar. Every design tool has a plugin for this now. There is no excuse.

Make touch targets at least 24 pixels, ideally 44. Apple's Human Interface Guidelines have said 44 points since the original iPhone. Your users have thumbs, sometimes gloves, sometimes one free hand, sometimes a tremor. Give them room.

Put primary actions where thumbs actually go. Bottom of the screen. Not the top-right corner, which is where design systems born on desktop laptops learned to put "Submit."

Caption the video. Transcribe the podcast. Write the alt text in the five seconds it takes. Mark the language with <html lang="en">. Don't remove the focus outline unless you're replacing it with something better.

That is, genuinely, most of it. There's more - skip links, reduced-motion queries, proper error messages, semantic landmarks - but if every team shipped just the list above, the WebAIM Million would look radically different next year.

The tests you're already writing are telling you something

Here's something I didn't understand for most of my career, and I want to save you a few years.

If you use React Testing Library (and you probably should), its whole philosophy is that your tests should find elements the same way a user does - by the label on the input, by the role of the button, by the text the user actually reads. Kent C. Dodds, who wrote it, calls this "the more your tests resemble the way your software is used, the more confidence they can give you."

What this means in practice is that an accessible component is trivial to test, and an inaccessible one is genuinely painful. The tests are trying to tell you something, and the message is: your users are going to have the same problem.

Watch what happens. Here's a login form built the hostile way:

jsx
// Inaccessible. The test is going to be ugly. Ask yourself why.
<div className="field">
  <span>Email</span>
  <input type="email" data-testid="email-input" />
</div>
<div className="btn" data-testid="submit-btn" onClick={handleSubmit}>
  Sign in
</div>

And the test you end up writing for it:

jsx
const emailInput = screen.getByTestId('email-input')
const submitBtn = screen.getByTestId('submit-btn')

await user.type(emailInput, 'alice@example.com')
await user.click(submitBtn)

This test passes. It also tells you nothing about whether a real human can use the form. A screen reader sees an unlabeled textbox and a <div> that isn't a button. The keyboard user can't reach the submit. The data-testid attributes exist solely because the component gave the test no other handle to grab - they are a workaround, smuggled into production HTML, for the absence of the semantic information that would also have made the component accessible.

Now the same form built the humane way:

jsx
// Accessible. And, not coincidentally, much nicer to test.
<label>
  Email
  <input type="email" name="email" />
</label>
<button type="submit">Sign in</button>

And the test:

jsx
const emailInput = screen.getByRole('textbox', { name: /email/i })
const submitBtn = screen.getByRole('button', { name: /sign in/i })

await user.type(emailInput, 'alice@example.com')
await user.click(submitBtn)

The test is the same length. But getByRole('button', { name: /sign in/i }) is asking a real question: is there a button, with the accessible name "Sign in," on this page? If a screen-reader user cannot find that button, this test fails. If a keyboard user cannot reach it, this test tells you. The test and the accessibility are the same property. You cannot accidentally ship one without the other.

This is why data-testid is a code smell. It's not wrong in absolute terms - sometimes you genuinely need it, for things with no semantic handle, like a specific list item in an otherwise identical grid. But most of the time, reaching for data-testid is the moment to stop and ask: hy can't I find this element the way a user would? he answer is almost always that you forgot a label, used a <div> instead of a <button>, or stripped out the semantics.

A few more queries worth knowing, in rough order of how often you should reach for them:

jsx
// getByRole — your default for almost everything interactive
screen.getByRole('button', { name: /save/i })
screen.getByRole('link', { name: /home/i })
screen.getByRole('heading', { level: 1, name: /dashboard/i })
screen.getByRole('checkbox', { name: /remember me/i })

// getByLabelText — for form fields. If this fails, your form is broken.
screen.getByLabelText(/email address/i)
screen.getByLabelText(/password/i)

// getByText — for static content the user reads
screen.getByText(/welcome back/i)

// getByAltText — for meaningful images
screen.getByAltText(/company logo/i)

Notice what's missing from that list: getByTestId. It exists in the library. It's the last resort. Testing Library's own docs call it "the last priority" and suggest you use it only when none of the accessible queries can reach your element - which, in a well-built component, should be almost never.

The rule I've settled on, and I'd recommend to any team: treat every new data-testid as a small failure requiring an explanation. Not a ban. A pause. "Why can't I query this by role or label?" The answer, ninety percent of the time, is a bug a real user is going to hit next Tuesday at 8:14 on the tram.

Your test suite is a free accessibility audit. You just have to let it do its job.

The curb cut

In 1972, in Berkeley, a man named Michael Pachovas and some friends poured a bag of cement into the gutter at the corner of Telegraph Avenue and made a ramp, because they were tired of being unable to cross the street in their wheelchairs. The city installed the first official curb cut that year. Within a decade they were everywhere.

A later study in Sarasota found that nine out of ten pedestrians without wheelchairs - parents with strollers, travelers with suitcases, skateboarders, couriers - went out of their way to use curb cuts when they were available. A thing built for a few thousand wheelchair users became infrastructure for everyone who has ever pushed a wheel across a curb.

That is the whole argument, in concrete. You build the ramp for the person who cannot use the step, and you discover that the people who could use the step were also, quietly, grateful not to.

The point

The next time someone on your team calls accessibility "nice to have," I want you to picture a very specific person. Not a stranger. You, next Tuesday, in the sun, at a parking meter, with a crying child on your hip and eleven seconds left on the timer. Or you, in fifteen years, squinting at your own banking app. Or you, right now, trying to validate a tram ticket before the inspector gets to your row.

Accessibility is not a favor we do for other people. It is the set of decisions that determine whether software still works when the human using it is temporarily a little bit tired, a little bit cold, a little bit old, a little bit overwhelmed, or just a little bit in the sun.

Which is to say: accessibility is whether software works for humans. All the rest is optimization for ideal conditions that no one actually lives in.

Discussion