Accessible & Inclusive. Design for every body, every device, every language.

About one in six people lives with a significant disability, and everyone has bad days: a broken wrist, a glaring sun, a crying baby on one arm, a 2G connection on a train. This guide teaches you to build products that still work in all of those moments. You will learn how assistive technology actually reads your interface, which WCAG 2.2 rules matter most for an app maker, and how to test it all alone in an afternoon.

Reading timeAbout 4 hours, in 5 sittings
Practice time2 weeks
Before thisThe Human Mind, Visual Design
TeachersKat Holmes, Microsoft Inclusive Design, W3C WAI, Léonie Watson, Heydon Pickering, Sara Soueidan, Patrick McKenzie

By the end you will be able to

  • Explain why accessibility is a design quality and not a compliance chore, using the persona spectrum and the curb-cut effect (understand)
  • Name the WCAG 2.2 success criteria that cause most real-world failures in apps, with their numbers: 4.5:1, 3:1, 24 px, 320 px, 200% (remember and understand)
  • Predict what a screen reader will announce for a piece of UI, by reasoning about role, name, state and reading order (analyse)
  • Design focus styles, targets, colour use, error messages and timing that work for keyboard, switch, voice and low-vision users (create)
  • Choose semantic HTML or native platform controls before ARIA, and know the keyboard contract of a dialog, menu, tab set and combobox (apply)
  • Run a complete solo accessibility audit of your own product in under two hours: automated scan, keyboard pass, screen-reader script, zoom and grayscale checks (evaluate)
  • Design for languages, scripts, right-to-left layouts, names, slow networks, cheap phones and older users (create)

Warm-up: what do you already believe?

Before you read, find out where your instincts are already right and where they are quietly wrong.

Most capable developers carry a handful of accessibility myths: that it is mostly about blind people, that it is a final checklist before launch, that adding ARIA makes things more accessible, that it makes interfaces ugly. Each of those beliefs produces specific bugs. Answer the three questions below without scrolling ahead. Getting one wrong is useful: it tells you which chapter to read most slowly.

Also recall two ideas from earlier guides, because this guide builds on them. From The Human Mind: working memory is small and attention is fragile, so every extra thing a person must hold in their head costs them. From Visual Design: hierarchy is made with size, weight, position and contrast, and colour is the weakest of those signals. Accessibility is what happens when you take both ideas seriously for people whose senses, hands or attention differ from yours.

Diagnostic 1

You add a delete icon button (a trash can SVG, no text) to every row of a list. Which single change helps the largest number of people?

Diagnostic 2

An automated scanner like axe or Lighthouse reports zero accessibility issues on your app. What can you honestly conclude?

Diagnostic 3

Which of these people does the WCAG "Reflow" requirement (content works at 320 CSS px wide without horizontal scrolling) help most directly?

How to study this guide: read one Part per sitting. Do each chapter's exercise on your own product before moving on; the exercises add up to a full audit and a fix list by the end. Keep a file called a11y-log.md open next to you and write every problem you find in it.
Part one

Why it matters and what "accessible" means

Accessibility is not a feature for a small group. It is the measure of how many situations your product survives. This part reframes disability as a mismatch between a person and a design, shows the legal and business ground under your feet, and gives you a compact map of WCAG 2.2 and colour contrast, the standard you will be measured against.

1

Disability is a mismatch, and it is common

Taught by Kat Holmes, with Microsoft Inclusive Design and Angela Glover Blackwell

Disability is not a property of a person; it is a mismatch between a person and the thing they are trying to use. Designers create those mismatches, so designers can remove them.

The World Health Organization estimates that about 1.3 billion people, roughly 16 percent of everyone alive, experience significant disability. That is the permanent slice. Add everyone who is temporarily injured, recovering from surgery, or just ageing (eyesight starts losing near focus in most people's forties) and the group grows. Add everyone in a situation that limits them for a few minutes, and the group becomes "all of your users, some of the time".

Kat Holmes, who led inclusive design at Microsoft, makes the point sharply in her book Mismatch (2018): the medical model treats disability as a condition inside a body, but the social model locates it at the point of contact between body and world. A wheelchair user is not disabled by a ramp. They are disabled by stairs. A blind user is not disabled by a well-labelled button. They are disabled by an unlabelled one. Every time you ship an icon with no name, you build a small staircase.

The persona spectrum

Microsoft's Inclusive Design toolkit (2016) gave designers a simple tool: for each human ability (touch, see, hear, speak) think of a permanent, a temporary and a situational version of the same limitation. A person with one arm, a person with a broken arm in a cast, and a parent holding a baby all need to use your app with one hand. Design for the permanent case and the other two come along for free. That is why the spectrum is useful: it turns a "niche" requirement into a mainstream one.

Permanent Temporary Situational Touch See Hear Speak One arm Arm in a cast Parent holding a baby Blind Cataract, dilated eyes Bright sunlight Deaf Ear infection Loud café or bar Non-verbal … Laryngitis ?! Strong accent, noisy room
The persona spectrum, after Microsoft's Inclusive Design toolkit. Read each row left to right: one design decision (one-handed use, captions, high contrast, typed input instead of voice) serves a small permanent group and a very large situational one.

The curb-cut effect

In the early 1970s, disability activists in Berkeley, California, pushed the city to cut ramps into sidewalk curbs so wheelchair users could cross streets. Once curb cuts existed, everyone used them: parents with strollers, travellers with suitcases, delivery workers with trolleys, kids on bikes. Angela Glover Blackwell named this pattern "the curb-cut effect" in a 2017 essay in the Stanford Social Innovation Review: designs made for a specific group routinely benefit far more people than intended.

Software is full of curb cuts. Captions were made for Deaf and hard-of-hearing viewers; today a large share of social video is watched with the sound off. Dark mode and "reduce motion" settings came out of accessibility needs and became mainstream preferences. Keyboard shortcuts help people who cannot use a mouse and make power users fast. Plain language helps people with cognitive disabilities and everyone reading in their second language, which in India is most people using English software.

curb cut wheelchair stroller suitcase bicycle In software: captions, made for Deaf viewers, also servemuted autoplay, noisy trains and language learners.
Built for one group, used by everyone. The yellow ramp is a tiny change to the curb. Most accessibility work in software is similarly small: a label, a focus style, a caption track.
Key idea

Solve for one, extend to many. Design for the permanent case and you cover the temporary and situational cases too.

What this means for your design process

Treat ability as a range, not a binary. Ask "what if this person cannot see the screen right now, cannot hear, cannot use a pointer, cannot read fast, cannot remember the last screen?" at the moment you design a flow, not after. Most fixes are cheap at sketch time and expensive after launch, because accessibility problems are rarely cosmetic: an unlabelled custom control, a gesture-only action, or a colour-only status are structural decisions.

Don't
(beep only)
Single channel. A timer that only beeps fails a Deaf user, a person in a loud kitchen, and anyone with the phone on silent.
Do
Rice is done 12:00 timer sound + text + haptic
Redundant channels. Sound, visible text and vibration together. Each one alone fails someone; together they fail almost no one.

Do

  • Ask the persona-spectrum question for every new flow: one hand, no sound, no sight, no pointer, low attention.
  • Send important signals through at least two channels (text plus colour, sound plus visual, icon plus label).
  • Respect the system settings people already chose: text size, reduce motion, increase contrast, dark mode.
  • Think of accessibility as product quality, measured like performance.

Don't

  • Treat disabled users as an edge case to handle "later".
  • Assume your users look like you: young, sighted, with a new phone and a fast connection.
  • Build a separate "accessible version"; it always falls behind the main one.
  • Confuse accessibility with a contrast slider bolted onto an otherwise unchanged design.

In the wild

  • VoiceOver on iPhoneApple, iPhone 3GS, 2009
    Apple shipped a full screen reader on a glass touchscreen that many blind people had assumed they could never use. Touch to explore, double-tap to activate. It became the default phone for a large part of the blind community. A platform that bakes accessibility into its standard controls makes every developer who uses those controls accessible by default.
  • Xbox Adaptive ControllerMicrosoft, 2018
    A controller with large programmable pads and ports for external switches, co-designed with gamers with limited mobility. Co-design with the people who face the mismatch, and the product gets better for everyone who can plug things into it.
  • Captions on social videoInstagram, TikTok, YouTube
    Automatic captions, first introduced for accessibility, are now a default way people watch muted video on commutes. A curb cut: the "accessibility feature" became core product behaviour.
For the solo creator

You cannot run a research programme with disabled participants every week. You can do three things that cost almost nothing: use your own phone with VoiceOver or TalkBack for ten minutes a week, use your product one-handed and with the screen at minimum brightness in daylight, and put "who does this fail?" at the top of every design note. That last habit catches more mismatches than any audit.

Common mistakes

"My users don't have disabilities"

It feels true because disabled users rarely email to say they left; they just leave. Many disabilities are invisible, and many users never disclose them.

Assume your audience matches the population: one in six with a significant disability, many more with situational limits. Design for that by default.

Accessibility as the last sprint

It is scheduled after "the real work" because it looks like polish. But it lives in structure: custom controls, gestures, flows.

Make it a design-time question and a definition-of-done item for every component. Retrofitting a custom dropdown costs ten times more than choosing a native select.

Designing only for blind users

Screen readers are the most visible assistive technology, so "accessibility" gets reduced to alt text.

Cover all four ability areas (vision, motor, hearing, cognition) plus situational limits. Low vision and cognitive needs affect far more people than total blindness.

Check yourself

You are designing a recipe app. Using the persona spectrum, which feature is the best "solve for one, extend to many" investment?

Exercise 1.1 30 minutes · on your own product

Your product's persona spectrum

  1. Draw a 4 by 3 grid (touch, see, hear, speak by permanent, temporary, situational) in your notes.
  2. For each cell, write one concrete moment when someone in that situation would use your product. Be specific: "reading a saved article on a crowded bus, one hand on the rail".
  3. For each moment, write the first thing in your current UI that would fail them.
  4. Circle the three failures that appear in more than one cell. Those are your highest-leverage fixes.
You're done when: you have a filled 12-cell grid and a ranked list of three cross-cutting fixes in your a11y-log.md.
BeginnerCompetentStrong
Grid filled with generic ability labels.Each cell is a concrete moment with a named UI failure.Fixes are ranked by how many cells they cover, and each has a rough effort estimate.
2

The law, the market, and the solo business case

Taught by W3C Web Accessibility Initiative, with the ADA, the European Accessibility Act and India's RPwD Act

Accessibility is increasingly a legal requirement for digital products, but the stronger reason for a solo creator is simpler: accessible products are better products, and they reach more paying people.

This chapter is orientation, not legal advice. Laws differ by country, change over time, and depend on who your customers are and how big your business is. What you need is a working map: which rules exist, which technical standard they almost all point to, and why the cost of complying is lowest if you design for it from the start.

The legal map in one picture

Nearly every accessibility law in the world, whatever its name, ends up pointing at the same technical yardstick: the Web Content Accessibility Guidelines (WCAG), usually at level AA. Learn WCAG once and you have learned the test that most regulators and courts use.

United States ADA (1990), Title III lawsuits ADA Title II rule (2024) for state and local government Section 508 (federal) European Union European Accessibility Act applies from 28 June 2025 e-commerce, banking, e-books, reading software, transport standard: EN 301 549 India RPwD Act 2016 (Sec. 40, 42) GIGW 3.0 (2023) for government sites and apps IS 17802 (ICT accessibility) WCAG, level AA
Different laws, one yardstick. Details vary (which version of WCAG, who is covered, exemptions for small firms), but designing to WCAG 2.2 AA puts you in good shape almost everywhere.

United States

The Americans with Disabilities Act (1990) predates the commercial web, and its Title III, covering "places of public accommodation", has been applied to websites and apps by many courts. Thousands of digital accessibility lawsuits are filed each year, many against small online stores. The best-known case, Robles v. Domino's Pizza, involved a blind customer who could not order through the website and app; in 2019 the Supreme Court declined to hear Domino's appeal, leaving in place a ruling that the ADA applied. In 2024 the Department of Justice adopted a rule requiring state and local government websites and apps to meet WCAG 2.1 AA. Section 508 covers federal agencies and what they buy.

European Union

The European Accessibility Act (Directive 2019/882) applies from 28 June 2025. It covers a defined list of products and services sold to consumers in the EU, including e-commerce, consumer banking, e-books and the software used to read them, electronic communications and parts of transport. Its technical standard is EN 301 549, which incorporates WCAG for web and app content. Microenterprises providing services (fewer than 10 staff and annual turnover or balance sheet of no more than €2 million) are exempt from the service requirements. If you are a one-person studio you are likely exempt today, but that changes the day you grow, sell through a larger partner, or a customer asks for a conformance report.

India

The Rights of Persons with Disabilities Act, 2016 requires accessibility in information and communication technology (sections 40 and 42 in particular) and the government publishes guidelines to implement it. The Guidelines for Indian Government Websites and Apps (GIGW 3.0, 2023) align with WCAG 2.1 for public-sector sites and apps, and the Bureau of Indian Standards publishes IS 17802, an ICT accessibility standard modelled on the European EN 301 549. If you build for Indian government, banks, or education, expect these to come up in procurement.

Watch out

"Accessibility overlay" widgets, the scripts that add a toolbar and promise instant compliance, do not fix inaccessible markup and are widely criticised by disabled users and accessibility practitioners. Several companies using them have still been sued. Fix the product itself.

The business case when you are one person

Large companies justify accessibility with risk and market size. Your case is more direct:

  1. Reach. One in six people, plus everyone over 50 losing near vision, plus everyone on a cheap phone in sunlight. Many of your competitors fail these people, so they look for the products that do not.
  2. Loyalty. Disabled users who find a product that works tend to stay, recommend it in their communities, and write the reviews that tell others it is safe to try. Word travels fast in small, connected communities.
  3. Quality. Accessible code is semantic, testable and resilient. Native buttons and labelled fields work with browser autofill, password managers, voice assistants, UI test tools and AI agents that operate interfaces through the same accessibility tree.
  4. Cost. Doing it at design time is nearly free. Retrofitting after launch, or after a demand letter, is slow and stressful, and you have no team to absorb it.
  5. Sales. Business and education buyers often ask for an accessibility conformance report (a VPAT or ACR). Having one lets a one-person product compete with bigger vendors.
Relative cost to fix the same problem (illustrative) SketchBuildAfter launchAfter complaint pick nativeadd labelsrewrite controlrush + legal
Shift it left. Choosing a native select in a sketch costs nothing. Rebuilding a custom dropdown after launch costs a week. These are relative shapes, not measured numbers.

Do

  • Target WCAG 2.2 AA from day one; it covers most laws.
  • Publish a short, honest accessibility statement: what you support, known gaps, how to contact you.
  • Keep an a11y-log.md of known issues and fix dates; it is your conformance report in embryo.

Don't

  • Install an overlay widget and call it done.
  • Claim "fully WCAG compliant" without having tested; a false claim is worse than an honest gap list.
  • Rely on a small-business exemption as a design strategy.

In the wild

  • GOV.UKGovernment Digital Service, UK, 2012 onwards
    Publishes an accessibility statement on its services, tests with disabled users, and open-sources an accessible design system that many governments copy. Being public about what works and what does not builds trust faster than a vague "we care about accessibility".
  • Domino'sUS, case decided on appeal 2019
    Years of litigation over a pizza ordering flow that a screen reader could not complete. The cheapest version of that fix was a labelled form in the first place.
  • E-reading apps in the EUEAA scope, 2025
    E-books and dedicated reading software are explicitly in scope: text must be resizable, readable by assistive technology, navigable. If you build reading tools (a natural fit for your taste), accessibility is part of the category's baseline.
For the solo creator

Write your accessibility statement now, even if it says "we are testing with VoiceOver and keyboard; known gaps: the chart view". It costs fifteen minutes, gives disabled users a way to reach you, and forces you to know your own gaps. Link it from your footer and settings.

Common mistakes

Buying an overlay

It promises compliance with one line of script, which is very tempting when you are alone.

Spend the same money and an afternoon on the solo audit in Chapter 15. Fix the source.

Treating the law as the ceiling

"AA" sounds like a finish line.

Treat AA as the floor. Some AAA criteria (7:1 body contrast, 44 px targets, no timing) are easy wins for a calm product.

Check yourself

A university in Pune wants to license your note-taking app for 4,000 students. Their procurement form asks about accessibility. What is the most useful thing to send?

Exercise 2.1 25 minutes · on your own product

Draft your accessibility statement

  1. Write one sentence on your target: "We aim to meet WCAG 2.2 level AA."
  2. List how you test (devices, screen readers, browsers).
  3. List known gaps honestly, with a target date for each.
  4. Give a contact method and a promised response time.
  5. Add it to your site footer or the app's About screen.
You're done when: a public or ready-to-publish statement of under 200 words exists, with at least two named gaps.
BeginnerCompetentStrong
Generic commitment, no gaps listed.Target, test method, gaps and contact all present.Gaps have dates and link to a public changelog; the statement is reachable in two taps from settings.
3

WCAG 2.2 for app makers, in one sitting

Taught by W3C WAI, with WebAIM

WCAG is organised around four principles: content must be Perceivable, Operable, Understandable and Robust (POUR). Around twenty of its success criteria cause most real-world failures in apps; learn those cold.

WCAG 2.2 became a W3C Recommendation in October 2023. It is backwards compatible: anything that meets 2.2 also meets 2.1 and 2.0. It has 86 success criteria (one older criterion, 4.1.1 Parsing, was removed as obsolete), each graded A, AA or AAA. Level A is the bare minimum, AA is what laws and contracts usually ask for, and AAA is a stricter set that is not required as a whole for entire sites because some content cannot meet it.

Do not try to memorise all 86. Understand the four principles as questions you ask of every screen, and memorise the handful of numeric thresholds, because numbers are where designs fail silently.

P O U R Perceivable Operable Understandable Robust Can people sense it? Alt text,captions, contrast, reflow. Can people use it? Keyboard,time, targets, gestures, focus. Can people follow it? Labels,errors, predictability, language. Does assistive tech get it?Name, role, value, status.
POUR as four questions. Ask them of every screen. Almost every success criterion is a specific answer to one of them.

The criteria that matter most for app makers

This table lists the criteria that cover the bulk of failures in real products, in the order you will meet them in this guide. Criteria new in 2.2 are marked. Memorise the numbers in bold.

CriterionLevelWhat it asks, in plain words
1.1.1 Non-text ContentAImages, icons and controls have a text alternative; decorative ones are hidden.
1.2.2 / 1.2.4 CaptionsA / AAPrerecorded video has captions (A); live video has captions (AA).
1.3.1 Info and RelationshipsAStructure you show visually (headings, lists, labels, tables) exists in code too.
1.4.1 Use of ColorAColour is never the only way to convey meaning.
1.4.3 Contrast (Minimum)AAText 4.5:1; large text (24 px, or 18.66 px bold) 3:1.
1.4.4 Resize TextAAText can scale to 200% without losing content or function.
1.4.10 ReflowAAWorks at 320 CSS px wide without two-way scrolling.
1.4.11 Non-text ContrastAAInput borders, focus indicators, icons and chart parts needed to understand them: 3:1.
1.4.12 Text SpacingAANothing breaks when users set line height 1.5, paragraph spacing 2×, letter spacing 0.12 em, word spacing 0.16 em.
2.1.1 Keyboard / 2.1.2 No TrapAEverything works by keyboard; focus can always leave a component.
2.2.1 Timing AdjustableATime limits can be turned off, adjusted or extended (warn, give at least 20 seconds to extend).
2.4.3 Focus Order / 2.4.7 Focus VisibleA / AAFocus moves in a sensible order and you can always see where it is.
2.4.11 Focus Not Obscured (Min.) newAAA focused element is not completely hidden by sticky headers, cookie bars or chat bubbles.
2.5.7 Dragging Movements newAAAnything done by dragging can also be done with single taps or clicks.
2.5.8 Target Size (Minimum) newAATargets at least 24 × 24 CSS px, or spaced so a 24 px circle around each does not overlap another.
3.2.6 Consistent Help newAHelp (contact, chat, FAQ) appears in the same relative place across pages.
3.3.1 Error Identification / 3.3.3 SuggestionA / AAErrors are described in text, and you suggest a fix when you know one.
3.3.2 Labels or InstructionsAInputs have visible labels or instructions.
3.3.7 Redundant Entry newADon't make people re-type information they already gave in the same process.
3.3.8 Accessible Authentication (Min.) newAALogin does not require a cognitive test (remembering, transcribing, puzzles) unless there is an alternative; allow paste and password managers.
4.1.2 Name, Role, ValueAEvery control exposes what it is, what it's called, and its state to assistive technology.
4.1.3 Status MessagesAAMessages like "Saved" or "3 results" are announced without moving focus.
2.5.8 Target Size (Minimum), drawn at 2× scale 24 × 24 px passes 16 px, spaced passes (circles don't overlap) 16 px, crowded fails
24 px is the floor, not the goal. Platform guidance is larger: Apple asks for 44 × 44 pt, Material Design for 48 × 48 dp. WCAG's AAA criterion 2.5.5 asks for 44 × 44 CSS px. Chapter 11 goes deeper.

How to read a criterion

Each criterion on the W3C site has an "Understanding" page that explains intent, who it helps, and examples, plus "Techniques" that show sufficient ways to meet it and common failures. When you are unsure whether something passes, read the Understanding page rather than a blog summary; the edge cases are written there. The W3C's "How to Meet WCAG (Quick Reference)" lets you filter by level and topic, which is the fastest way to build your own short list.

What about WCAG 3?

W3C is developing WCAG 3, a different structure with outcomes and a new scoring model. As of late 2026 it is still a Working Draft, not a standard, and laws do not reference it. Read it to understand where things are heading; build to 2.2 AA.

Do

  • Learn the numbers: 4.5:1, 3:1, 200%, 320 px, 24 px, 20 seconds.
  • Read the Understanding page when in doubt.
  • Map your components to criteria once (button: 2.1.1, 2.4.7, 2.5.8, 4.1.2) and reuse the map.

Don't

  • Treat WCAG as the whole of usability; a page can pass and still be confusing.
  • Read success criteria as loopholes ("it says 'only', so…").
  • Ignore AAA entirely; several items are cheap for a calm, minimal product.

In the wild

  • The WebAIM MillionWebAIM, annual since 2019
    An annual automated scan of the top million home pages. Every year around 95 percent have detectable WCAG failures, and the same six problem types dominate: low-contrast text, missing alt text, missing form labels, empty links, empty buttons and missing page language. Fix those six and you are ahead of almost the entire web.
  • GOV.UK Design SystemUK Government Digital Service
    Each component page lists the research and accessibility findings behind it. Document which criteria each of your components satisfies; your future self is your team.
For the solo creator

Print or pin the table above. When you build a new component, scan it for the rows that apply and test those specific things. Twenty rows is a manageable personal standard; eighty-six is not.

Common mistakes

Confusing "large text" with "big enough"

The 3:1 allowance is for text 24 CSS px and up (or about 18.66 px bold). Designers apply it to 18 px regular labels.

Body copy and UI labels at normal sizes need 4.5:1. Check the actual rendered size.

Forgetting non-text contrast

Text gets checked, but input borders at #E5E5E5 on white, faint toggle tracks and focus rings slip through.

Anything a person must see to operate a control needs 3:1 against what is next to it.

Sticky things hiding focus

Sticky headers and footers are added late and nobody tabs behind them.

Use CSS scroll-padding-top equal to the sticky header height and tab through every page after adding a sticky element.

Check yourself

Your sign-in screen sends a 6-digit code by SMS and has a "paste" blocker on the field "for security". Which criterion does the paste blocker most directly hurt?

Exercise 3.1 40 minutes · on your own product

Your personal WCAG short list

  1. List your five most-used components (for example: button, text field, list row, modal, tab bar).
  2. For each, write which rows from the table above apply.
  3. For three of them, read the W3C "Understanding" page of one criterion you were least sure about.
  4. Write down one thing you learned that changed your mind.
You're done when: you have a component-to-criteria map with at least 15 entries and three notes from Understanding pages.
BeginnerCompetentStrong
Criteria named without mapping to components.Each component mapped to specific criteria with the numeric threshold.Map includes a test method for each entry and you found at least one current failure.
4

Contrast: the ratio, the reason, and APCA

Taught by W3C WAI, with Andrew Somers (APCA) and Lea Verou

Contrast is the difference in lightness between text and its background. Below a threshold, reading becomes slow and tiring for everyone and impossible for some; WCAG sets that threshold at 4.5:1 for body text.

Our eyes are far more sensitive to differences in lightness (luminance) than to differences in hue. Contrast sensitivity also falls with age, with conditions like cataracts and glaucoma, with screen glare, and with cheap displays. A pale grey that looks elegant on your calibrated monitor at night can vanish on a budget phone in the afternoon sun. Low-contrast text is the single most common failure on the web in WebAIM's yearly scans.

How the WCAG ratio works

The formula converts each colour to relative luminance: it undoes the sRGB gamma curve, then weights the channels by how sensitive the eye is to each (roughly 21% red, 72% green, 7% blue). The ratio is (L1 + 0.05) / (L2 + 0.05), where L1 is the lighter colour. It runs from 1:1 (identical) to 21:1 (black on white). The 0.05 term models a little ambient light falling on the screen.

The WCAG contrast scale (not linear in feel) 1:121:1 3 4.5 7 3:1 large text (24 px+), icons, borders, focus rings4.5:1 body text (AA) · 7:1 body text (AAA)
The thresholds sit low on the scale. 4.5:1 is only about a fifth of the way along. Most "too light" greys fall between 2:1 and 4:1.

Lab: check any pair of colours

Pick a text colour and a background. The lab computes the WCAG 2 ratio live and gives verdicts for body text, large text and UI components. Try the presets, then try to find the lightest grey on white that still passes 4.5:1 (it is close to #767676).

Lab: contrast checker

Large heading, 24 px

Body text at 16 px. Reading this paragraph should feel effortless, even on a phone outdoors.

Small caption, 12 px

Button outline
Contrast ratio
–
#8a8a8a
#ffffff
Things to notice: white on yellow fails badly while dark ink on the same yellow passes easily. White on a bright saturated blue fails body text but passes for large text. The "input border" preset shows why faint field outlines fail the 3:1 non-text rule.

Where the WCAG 2 formula is imperfect

The WCAG 2 formula is simple and widely implemented, but it has known weaknesses. It treats a pair the same whichever colour is the text, while real perception differs between dark-on-light and light-on-dark. It tends to overstate the contrast of dark colour pairs (some dark greys on black pass on paper but are hard to read) and can understate some mid-tone pairs, such as white text on certain oranges and blues that many people find perfectly readable. It also ignores font size and weight beyond the single "large text" threshold, though thin, small text needs much more contrast than bold, large text.

APCA: an emerging model, honestly described

The Accessible Perceptual Contrast Algorithm (APCA), developed by Andrew Somers, tries to model perceived lightness contrast more accurately. It is polarity-aware (dark text on light is scored differently from light text on dark), reports a value called Lc (lightness contrast) from roughly 0 to about 106 for dark-on-light, and links the required contrast to font size and weight through lookup tables. As a rough guide from its documentation, Lc 90 is preferred for body text, Lc 75 is a minimum for body text, and lower values are acceptable for large or bold text and non-text elements.

Its status matters. APCA has appeared in drafts and discussions around WCAG 3, but it is not part of any W3C Recommendation, WCAG 3 is still a Working Draft, and no law references APCA. The honest practice in 2026 is: meet WCAG 2 ratios because that is what you are measured against; use APCA as a second opinion, especially for dark mode and for thin or small type, where WCAG 2 can approve combinations that are actually hard to read.

Don't

Your export finished. 3 files were saved to Downloads. Tap to open the folder.

Last synced 2 min ago

Thin, small and pale. Light weight, 13 px and a faded grey stack three penalties. Each alone is survivable; together the text dissolves.
Do

Your export finished. 3 files were saved to Downloads. Open folder

Last synced 2 min ago

Hierarchy through size and weight. The secondary line is still muted, but uses a muted colour that passes 4.5:1. Calm does not require faint.
Myth

"High contrast looks harsh." Pure black on pure white at large sizes can glare, and many calm products use a near-black on an off-white (this course uses an ink of about 15:1 on its paper). That is still far above 4.5:1. Calm comes from restraint in the number of colours and weights, not from washing out text.

Do

  • Define a muted text token that passes 4.5:1 on every surface it sits on, in light and dark themes.
  • Check placeholder text, disabled-looking labels, captions and timestamps; they fail most often.
  • Test text on images with the worst part of the image, or add a scrim.
  • Respect "Increase contrast" (iOS) and prefers-contrast: more with a slightly stronger palette.

Don't

  • Use light font weights (300 and below) for body text at small sizes.
  • Put white text on yellow, light orange or light green buttons.
  • Rely on opacity to make text secondary; the result varies by background.
  • Use placeholder text as the only label (it is usually too light, and it disappears).

In the wild

  • iOS "Increase Contrast"Apple
    A system setting that apps can read; native controls and system colours automatically switch to higher-contrast variants. If you use semantic system colours instead of hard-coded ones, you inherit this for free.
  • Windows contrast themesMicrosoft
    Users can force a limited, high-contrast palette across apps; on the web this appears as the forced-colors media query. Use real borders and outlines, not only background colours and box shadows, so controls keep their shape when colours are replaced.
  • iA WriterInformation Architects
    Near-black text on an off-white paper and a carefully tuned dark mode; the calm comes from type and space, not from low contrast. Minimal and accessible are allies.
For the solo creator

Put contrast checks into your tokens, not your screens. Write a tiny script (or a test) that computes the ratio for every text token on every surface token in both themes and fails the build below 4.5:1. You will never hand-check a timestamp again.

Common mistakes

Checking light mode only

Dark themes are often made by inverting and dimming, and muted greys end up too dark against near-black.

Check every token pair in both themes. Dark mode muted text usually needs to be lighter than you expect.

Brand colour as button fill with white text

The brand colour was chosen for a logo, not for text contrast.

Keep the brand hue but derive a darker shade for fills behind text, or use dark text on the brand colour (this course's yellow buttons use dark ink).

Disabled states that are unreadable

WCAG exempts inactive controls from contrast, so they are made very faint.

Exempt does not mean ideal. People still need to read a disabled button to know what they are missing; explain why it is disabled nearby.

Check yourself

Your dark theme uses #A3A6AB muted text on #151617. A checker says about 7.4:1. A friend says some small, thin labels in that colour still feel hard to read. What do you do?

Check yourself

Your text field has a 1 px #E5E5E5 border on white and a light grey placeholder "Email". Which change fixes the most criteria at once?

Exercise 4.1 45 minutes · on your own product

Contrast audit of your tokens

  1. List every text colour token and every surface colour token in your product, for both themes.
  2. Use the lab above or a checker to compute every pairing that actually occurs.
  3. Mark each as pass or fail for its use (body 4.5:1, large 3:1, UI parts 3:1).
  4. For every fail, propose the smallest change that passes while keeping the feel.
  5. Bonus: write the 15-line script that recomputes this table on every build.
You're done when: you have a table of token pairs with ratios and verdicts, and every failing pair has a replacement value.
BeginnerCompetentStrong
Main text colours checked in one theme.All text and UI pairs in both themes checked and fixed.Checks are automated in the build, and APCA was used as a second opinion for dark mode.

Part one recap: connect the ideas

Recap

In Visual Design you learned to build hierarchy with size, weight, position and contrast. Which statement best connects that guide to this part?

Part two

Seeing and hearing

Vision and hearing differences are where most people start, and where the mechanics of assistive technology are clearest. You will learn how zoom and large text break layouts, why colour must never work alone, exactly what a screen reader reads and in what order, how to write alt text that helps, and how to make sound visible.

5

Low vision: zoom, large text and reflow

Taught by W3C WAI, with Apple Human Interface Guidelines and Material Design

Many more people have low vision than are blind, and most of them use what they already have: bigger text and zoom. Your job is to make sure your layout survives both without clipping, overlapping or scrolling sideways.

Low vision covers blurred vision, loss of central vision (macular degeneration), loss of peripheral vision (glaucoma), light sensitivity and reduced contrast sensitivity. Add the age-related loss of near focus (presbyopia) that affects nearly everyone from their mid-forties, and a large share of your users will prefer text bigger than your default. On phones they raise the system text size. On desktops they use browser zoom, sometimes up to 400%, or a screen magnifier that shows a small portion of the screen enlarged.

Two mechanisms matter. First, text scaling: the system or browser makes text larger while the rest of the layout stays the same size, unless you sized it relative to text. Second, zoom: the whole page scales, which on the web shrinks the effective viewport (1280 px at 400% is a 320 px viewport). Layouts break in predictable ways under each: fixed heights clip text, fixed widths force sideways scrolling, absolute positioning makes things overlap, and truncation hides the very words people zoomed in to read.

100% text200%, fixed height200%, grows with content text cut off below the edge Use min-height, not height. Let containers grow; let rows wrap.
Fixed boxes are the enemy of large text. The same card at 200%: the fixed-height version hides the content people enlarged it to read.

Lab: zoom and reflow

The frame below is a small app screen. Use the sliders to shrink the viewport (as zoom does) and enlarge the text (as Dynamic Type or browser text size does). Switch between a layout built with fixed sizes and one built to reflow. Push it to 320 px and 200% and watch what each layout does.

Lab: text zoom and reflow
Viewport 560 px · text 100%
LibraryHighlightsCollectionsSettings
The Shape of Design

Frank Chimero's short book about why we make things, and how to make them well. Saved Tuesday, 42 minutes left.

Continue readingShare highlightsArchive
Fixed sizes: the card has a set height and the button row a set width. At large text the card clips and the row forces sideways scrolling, failing 1.4.4 and 1.4.10. The reflowing layout uses min-height, wrapping rows and flexible tabs, so it just gets longer. On narrow screens the frame may already be narrower than the slider value.

Dynamic Type and its equivalents

On iOS, Dynamic Type offers seven standard sizes plus five larger accessibility sizes; at the largest, body text is roughly three times the default. SwiftUI text styles (.font(.body), .headline) scale automatically, and @ScaledMetric scales your own spacing and icon sizes with them. On Android, use sp units for text so it follows the user's font scale, which recent Android versions allow up to 200%. On the web, size text in rem and let the user's browser default (usually 16 px) be the base, and do not set maximum-scale=1 or user-scalable=no in the viewport meta tag, which blocks pinch zoom.

Default text: horizontal row Daily goal20 min Accessibility size: stacked Daily goal 20 min At large sizes, side-by-side rows squeeze both texts into truncation. Switch the row to a vertical stack (SwiftUI: ViewThatFits or a check on dynamicTypeSize.isAccessibilitySize).
Adapt, do not just enlarge. Apple's own Settings app stacks rows at accessibility sizes. Plan a stacked variant for every horizontal row.
Don't
The Shape… LibraHighSett
Truncation and collision. Ellipses hide the words people enlarged; the tab bar labels run into each other.
Do
The Shapeof Design
Wrap and adapt. Titles wrap to more lines; the tab bar keeps icons and shows a large label on long press, as iOS does with its large content viewer.

Do

  • Size text in rem (web), sp (Android) or text styles (iOS), never fixed pixels or points.
  • Use min-height and let containers grow; let flex rows wrap.
  • Test at 200% text and at 400% browser zoom (or a 320 px window).
  • Let long titles wrap to two or three lines before truncating.

Don't

  • Disable pinch zoom.
  • Put text inside images or canvas where it cannot scale.
  • Cap Dynamic Type at the default range "because the design breaks"; fix the design.
  • Use horizontally scrolling carousels as the only way to reach content.

In the wild

  • iOS Settings and MailApple
    At accessibility text sizes, rows stack their label and value vertically rather than truncating both. Plan a second layout for large text instead of letting the first one crush.
  • Kindle and Apple BooksAmazon, Apple
    Readers can change font, size, line spacing and margins; the text reflows into pages. Reflowable text is the most accessible format there is. Fixed-layout PDFs are the opposite.
  • Zoom and MagnifiermacOS, iOS, Windows, Android
    Built-in screen magnifiers follow keyboard focus and the text cursor. When focus moves predictably, magnifier users see what changed; when you update a distant part of the screen silently, they miss it.
For the solo creator

Add two permanent previews to your development setup: one at the largest accessibility text size and one in a 320 px wide window. SwiftUI previews can pin .dynamicTypeSize(.accessibility3); on the web, keep a narrow browser window open beside your editor. Bugs you see every day get fixed; bugs you check once a quarter do not.

Common mistakes

Fixed-height cards and buttons

Heights are copied from the design file, where text was one size.

Use padding plus min-height. Let the content define the height.

Single-line truncation everywhere

It keeps lists tidy at default size.

Allow two or three lines (CSS line-clamp, SwiftUI lineLimit(3)) and offer the full text on the detail screen.

Breakpoints in px, text in rem

When users raise their default font size, px media queries do not respond and the wide layout gets cramped.

Write media queries in em or rem so they respond to text size, or use container queries.

Check yourself

A user with low vision says your web app "gets cut off on the right" when they zoom to 300%. What is most likely wrong?

Exercise 5.1 45 minutes · on your own product

The 200 / 400 test

  1. Set your phone to the largest text size (iOS: Accessibility > Display & Text Size > Larger Text; Android: Font size and Display size to maximum).
  2. Walk through your three most important screens. Screenshot every clip, overlap and truncation.
  3. On desktop, zoom the browser to 400% (or resize to 320 px) and repeat. Note any horizontal scrolling.
  4. For each problem, write the CSS or layout change that fixes it.
You're done when: you have a list of screenshots with fixes, and at least the top three are fixed and re-tested.
BeginnerCompetentStrong
Problems found on one platform.Both text scaling and zoom tested, top issues fixed.Large-text and narrow previews added to your daily workflow so regressions show up immediately.
6

Colour vision: never let colour work alone

Taught by W3C WAI (1.4.1 Use of Color), with Masataka Okabe and Kei Ito (colour-blind-safe palettes)

About one in twelve men and one in two hundred women of Northern European ancestry have some form of colour vision deficiency. If colour is the only thing that distinguishes "error" from "success" or one chart line from another, those people cannot tell them apart.

Most of us have three kinds of cone cells, sensitive roughly to long (red), medium (green) and short (blue) wavelengths. Colour vision deficiency happens when one kind is missing or shifted. The common forms are inherited and carried on the X chromosome, which is why far more men are affected.

Deuteranomaly / deuteranopia
Medium-wavelength (green) cones shifted or missing. The most common form. Reds, greens, oranges and browns collapse toward similar olive and yellow tones.
Protanomaly / protanopia
Long-wavelength (red) cones shifted or missing. Similar confusion to deuteranopia, and reds also look darker, so red text on black can nearly disappear.
Tritanomaly / tritanopia
Short-wavelength (blue) cones affected. Rare. Blues and greens, and yellows and pinks, become confusable.
Achromatopsia
Very rare total colour blindness, often with light sensitivity. The world appears in shades of grey.

The practical rule, WCAG 1.4.1, is simple: colour may reinforce meaning but must not carry it alone. Pair it with text, an icon, a shape, a pattern, a position or an underline. This also helps people on monochrome e-ink screens, people in bright sunlight, people with night-shift filters, and anyone who prints your page in black and white.

Lab: see your status UI through other eyes

This build status board and chart use the classic red and green. Choose a type of colour vision to apply an approximate simulation (an SVG colour matrix filter), then switch to the redundant design that adds icons, labels and line patterns.

Lab: colour vision simulator
Builds iOS appAndroid appWebAPI PassedFailedPassedFailed 2 of 4 builds need attention Sign-ups vs. cancellations Sign-ups Cancellations Sign-ups Cancellations

Typical colour vision.

Simulations here are approximations of the full forms (dichromacy). Milder forms (the "-anomaly" types) are more common and sit between typical vision and these images. The point is not exact appearance but whether meaning survives. In redundant mode the line chart is directly labelled, uses different markers, and the status board says "Passed" or "Failed".

Techniques that make colour redundant

TextPaid Shape Pattern Direct labelsPlan A Underline linksRead thefull terms PositionSaveCancel
Six ways to carry meaning without hue. Use at least one alongside colour. Links inside body text should be underlined (or have 3:1 contrast with surrounding text plus a non-colour cue on hover and focus).
Don't
rohit@example
••••••••
Red border only. A colour-blind user, a screen-reader user and someone in sunlight all miss which field is wrong and why.
Do
rohit@example
! Add the part after the dot, like rohit@example.com
••••••••
Border, icon and message. The error is identified in text (3.3.1) and suggests a fix (3.3.3). The message is tied to the field with aria-describedby.

Do

  • Add a text label or icon to every colour-coded status.
  • Label chart lines directly and vary markers or dash styles.
  • Choose palettes that differ in lightness, not just hue (the Okabe–Ito palette is a well-known colour-blind-safe set).
  • Check screens in grayscale (most OSes have a colour filter setting).

Don't

  • Use red versus green as the only difference between good and bad.
  • Rely on legend colour keys for more than three or four series.
  • Remove underlines from links in running text without another non-colour cue.
  • Assume dark mode fixes colour problems; it often makes reds darker and harder to see.

In the wild

  • WordleJosh Wardle, 2021; New York Times since 2022
    Offers a high-contrast mode that swaps green and yellow for orange and blue, so the three tile states differ strongly in lightness and hue. A simple palette switch can rescue a game whose entire feedback is colour.
  • GitHubColour-blind themes
    Offers light and dark themes tuned for protanopia/deuteranopia and for tritanopia, which change the diff and contribution-graph colours. If your product leans on status colour, give it a themed alternative, not just a note.
  • TrelloAtlassian
    Has offered a colour-blind friendly mode that adds patterns to coloured card labels. Patterns survive any colour filter, print and e-ink.
For the solo creator

Turn on your phone's grayscale filter (iOS: Accessibility > Display & Text Size > Color Filters; Android: Color correction or Grayscale in Digital Wellbeing) for one day a month. If you cannot tell states apart, neither can a part of your audience. It costs nothing and you will spot problems in minutes.

Common mistakes

Traffic-light status dots

Red, amber, green feels universal to the designer.

Add words ("Failed", "Running", "Passed") or distinct shapes (cross, clock, tick). Words also help screen readers.

Required fields marked only in red

An old convention from forms.

Write "(required)" or, better, mark the optional fields with "(optional)" when most are required.

Charts with a legend of six colours

Chart libraries default to it.

Direct-label lines, limit to a few series, and highlight the one that matters in a strong colour with the rest in grey. See Information & Data.

Check yourself

Your habit tracker shows completed days as green squares and missed days as red squares in a calendar grid. What is the smallest change that makes it work for deuteranopia and grayscale?

Exercise 6.1 30 minutes · on your own product

The grayscale pass

  1. Turn on grayscale on your phone or computer.
  2. Open every screen that uses colour to show status, category, selection, errors or data.
  3. For each, ask: can I still tell the states apart and know what they mean?
  4. Add one non-colour cue to every place that fails, and re-check.
You're done when: every colour-coded meaning in your product has a second cue, verified in grayscale.
BeginnerCompetentStrong
Errors fixed, charts and tags not checked.All statuses, tags and charts have a second cue.Palette re-chosen for lightness differences; you documented the rule in your design tokens file.
7

How screen readers actually work

Taught by Léonie Watson, with W3C WAI-ARIA and WebAIM

A screen reader does not read your pixels. It reads a parallel structure, the accessibility tree, in which every meaningful element has a role, a name, a state and a place in order. If you get those four right, the experience follows.

When your app renders, the browser or operating system builds two things: the visual layout and an accessibility tree. The tree is a simplified version of your interface that platform accessibility APIs expose to assistive technology: NSAccessibility and UIAccessibility on Apple platforms, AccessibilityNodeInfo on Android, UI Automation and IAccessible2 on Windows. Screen readers, voice control, switch control and automated test tools all read this tree. Purely decorative elements are dropped; generic containers mostly disappear; buttons, links, headings, fields and landmarks remain.

What you see Notes Search Groceries Trip ideas What a screen reader gets main (landmark) heading, level 1, "Notes" search field, "Search notes" list, 2 items link, "Groceries" link, "Trip ideas" button, no name announced as "button", or the file name of the icon
The accessibility tree is your real interface for assistive technology. The plus button looks obvious to you; in the tree it is a nameless button. Fix: an accessible name like "New note".

Role, name, state, value

Every interactive node needs four answers. Role: what kind of thing is it (button, link, checkbox, tab, slider, heading)? The role tells users what they can do with it and tells the screen reader which keys work. Name: what is it called ("Save", "Search notes", "Groceries")? State: is it checked, expanded, selected, pressed, disabled, busy? Value: for things like sliders and text fields, what is the current value? WCAG 4.1.2 Name, Role, Value is the criterion behind all of this.

A screen reader combines them into an announcement, usually in the order name, role, state, sometimes followed by a hint. VoiceOver on iOS might say "Dark mode, switch button, on. Double-tap to toggle setting." NVDA on Windows might say "Dark mode, toggle button, pressed". The exact words differ between screen readers and versions; the information is the same.

The accessible name is computed by a defined algorithm (the W3C's Accessible Name and Description Computation). In practice, the main sources in priority order are: aria-labelledby (text of other elements), aria-label, the native label (a <label> for an input, alt for an image), the element's own text content for buttons, links and headings, and finally title or placeholder as weak fallbacks.

Demo: what does it announce?

The two panes below contain real, live HTML: the same six controls written badly and written well. A small script walks each element and computes a simplified name, role and state, the way a screen reader would, and prints the announcement. Tab into the controls in each pane to hear (read) what a screen-reader user would hear on focus.

Accessible name inspector
Settings
Email
Dark mode ●
Click here
ElementAnnounced
Focus a control to see its announcementTab or click into the controls above
Without: a div with an icon has no role and no name; the "heading" is just bold text; the label is not connected to the field; the toggle is a div with a dot; "Click here" means nothing out of context; the image has a role but no description.

Reading order, headings and landmarks

Screen-reader users rarely listen to a page from top to bottom. They skim, like sighted users do, but with the keyboard or gestures: jump from heading to heading (the H key in NVDA and JAWS, the rotor on VoiceOver), jump between landmarks (main, navigation, search, banner, contentinfo), or pull up a list of all links. In WebAIM's screen-reader surveys, navigating by headings has consistently been the most common way to find information on a long page, used by roughly two thirds or more of respondents. So your headings are your table of contents.

Reading order follows the order in the code (DOM order on the web, view hierarchy order on iOS and Android), not the visual position. If you use CSS grid, order, absolute positioning or flex reversal to move things visually, the screen reader will still read them in source order. Keep the source order the same as the visual order.

header · banner landmark navnavigation main h1 Your library h2 Continue reading h2 Recently saved h3 per article… asidecomplementary footer · contentinfo landmark
Landmarks and headings are the map. Use one h1 per page, h2 for main sections, h3 below them, without skipping levels for visual size. Use HTML5 elements (header, nav, main, aside, footer) and you get landmarks for free.

Meet the main screen readers

VoiceOver is built into every Apple device. On iPhone: Settings > Accessibility > VoiceOver, or set the Accessibility Shortcut to a triple-click of the side button. Swipe right or left to move to the next or previous element, double-tap to activate, rotate two fingers to open the rotor and pick "Headings", then swipe up or down to jump between them. On Mac, Command-F5 toggles it; VO keys are Control-Option.

Do

  • Give every control a role, a clear name and its state.
  • Use real headings in a logical outline; one h1 per screen.
  • Keep DOM order equal to visual order.
  • Announce async results ("Saved", "3 results") with a polite live region or the platform's announcement API.

Don't

  • Repeat the role in the name ("Delete button button").
  • Use headings for styling or skip levels for size.
  • Hide content with aria-hidden that is still focusable.
  • Rearrange visual order with CSS so it no longer matches reading order.

In the wild

  • iOS rotorApple
    A two-finger rotation gesture that picks a navigation unit (headings, links, form controls, words) and then swipes by that unit. Structure you mark up becomes navigation the user controls.
  • Be My Eyes2015; Be My AI 2023
    Connects blind and low-vision users with sighted volunteers over video, and later added an AI image describer. Its own interface is built from standard, well-labelled controls. The most loved tools in the community are not fancy; they are predictable.
For the solo creator

Set your phone's accessibility shortcut (triple-click) to toggle VoiceOver or TalkBack. Ten seconds to turn it on means you will actually test with it. Learn just five gestures: swipe next, swipe previous, double-tap, rotor or reading control, and two-finger swipe up (read all). That is enough to find most problems.

Common mistakes

Clickable divs

Frameworks make it easy to put an onClick on anything.

Use button for actions and a for navigation. They come with role, focus and keyboard handling. A lint rule (eslint-plugin-jsx-a11y, for instance) catches most cases.

Visual headings that aren't headings

Bold divs look right in the design.

Use h1 to h6 and style them. Screen-reader users navigate by them.

Silent updates

"Saved" toasts and result counts appear visually only.

Use a role="status" region (polite) for confirmations and role="alert" only for urgent errors. On iOS post UIAccessibility.post(notification: .announcement, ...) or use SwiftUI's accessibility announcement support.

Check yourself

Your card grid uses CSS order to show the "Featured" card first visually, but it is last in the HTML. What does a screen-reader user experience?

Check yourself

A button contains a heart icon and the visible text "12". What should its accessible name be?

Exercise 7.1 60 minutes · on your own product

Eyes-closed task

  1. Turn on VoiceOver or TalkBack. Turn on Screen Curtain (VoiceOver: three-finger triple-tap) so the screen goes dark.
  2. Try to complete your product's single most important task.
  3. Write down every element whose announcement was missing, unclear, redundant or out of order.
  4. Turn off the curtain, and for each problem write its cause in terms of role, name, state or order.
  5. Fix the three worst. Repeat the task.
You're done when: you can complete your core task with the screen dark, and your log lists each problem with its cause.
BeginnerCompetentStrong
Task attempted with the screen visible.Task completed eyes-closed; problems classified by role, name, state, order.All problems fixed; you added a test (UI test or snapshot of the accessibility tree) to prevent regressions.
8

Writing alt text and labels that help

Taught by W3C WAI images tutorial, with WebAIM

A text alternative should do the job the image does, in the context where it appears. Describe the purpose, not the pixels; and say nothing at all for images that are purely decorative.

Alt text is writing, and it follows the same rule as all UI writing in Words: say what the reader needs, in as few words as possible. The trick is to ask "what would I say if I were reading this screen aloud to a friend on the phone?" For a logo in a header that links home, you would say the product name. For a photo of a recipe step, you would describe what the cook should notice. For a decorative flourish, you would say nothing.

Purely decorative? Empty alt: alt="" (or aria-hidden) Contains text? Alt repeats the text, exactly Is it a link or button? Describe the action or destination Complex (chart, map)? Short alt + longer description nearby Otherwise: describe what it means here, in one or two sentences. yesyesyesyesnononono
A decision tree, after the W3C images tutorial. Walk it top to bottom for every image. Most images in apps are either decorative or functional (icons in buttons).

Worked examples

Context changes everything. The same photo of a person reading on a balcony needs different alt text in different places.

Image and contextWeak altBetter alt
App logo in header, links to home"logo.png""Margins, home"
Trash icon in a button"trash can icon""Delete highlight"
Photo of a person reading on a balcony, on a landing page hero"image of woman""" (decorative, if the headline already says what the product does) or "A reader on a sunny balcony, phone in one hand"
Same photo in a news story about urban heat"woman reading""A woman reads under an umbrella on a Delhi balcony as temperatures pass 45°C"
Bar chart of weekly reading time"chart""Reading time rose from 2 to 5 hours a week between January and March." plus a data table below
Screenshot of an error dialog in a help article"screenshot""Dialog reading: 'Sync failed. Your device is offline.' with Retry and Cancel buttons"
Decorative divider flourish"decorative line""" (empty alt)

A few rules of thumb. Don't start with "image of" or "picture of": the screen reader already says "image". Put the most important information first; people can stop listening. Keep it short (a sentence or two) and move longer explanations into visible text, which helps everyone. Include text that appears in the image. Don't describe what the surrounding text already says. For people in photos, describe what is relevant to the context; avoid guessing identity attributes like race or gender unless they matter to the meaning and you know them.

Don't
"icon-trash-24 dot svg, button"
File name. No alt or name: some screen readers read the file name or URL.
Don't
"Trash can icon, button"
Describes the picture. Accurate, but the user wants to know what it does, and to what.
Do
"Delete highlight, button"
Names the action and object. In a list, include which item: "Delete highlight from chapter 3".

User-generated images

If your product lets people upload images, you share responsibility for their alt text. Offer an alt-text field at upload time, make it easy to reach, and consider a gentle reminder before posting. Automatic descriptions (from on-device or cloud image models) are useful as a starting suggestion, but they miss context and can be wrong; label them as automatic and let people edit.

Do

  • Write alt text for function in context.
  • Use empty alt (alt="") for decorative images so they are skipped.
  • Hide decorative SVG icons inside labelled buttons with aria-hidden="true".
  • Give charts a short summary plus an accessible table of the data.

Don't

  • Leave alt off entirely (different from empty).
  • Stuff keywords into alt text for SEO.
  • Repeat the caption in the alt.
  • Put essential text only inside images.

In the wild

  • Mastodon and Bluesky2016 onwards; 2023 onwards
    Both put an image-description field in the composer, and community norms push people to use it; some clients can remind you before you post an image without one. Product design can build a culture: make the right thing visible at the moment of action.
  • InstagramMeta, 2018
    Added automatic alt text from object recognition and a field to write your own under Advanced settings. Automation helps at scale, but buried manual fields get little use. Put the field where people already are.
  • Seeing AIMicrosoft, 2017
    A camera app that narrates text, scenes, products and people for blind users. Users already carry tools that describe images; your alt text should add the meaning only you know.
For the solo creator

Make alt text a required field in your own content pipeline: if your landing page or docs are generated from Markdown, write a check that fails the build when an image has no alt attribute (empty alt is allowed, but it must be deliberate). You will write better descriptions when you are forced to think about each image.

Common mistakes

Alt on the image and a label on the button

Both added "to be safe".

Name the control once. Hide the inner image (empty alt or aria-hidden) so it does not double the announcement.

Novels in alt attributes

Over-correction after learning alt text matters.

One or two sentences. Long descriptions belong in visible text or an expandable "Describe this chart" section.

Check yourself

Your onboarding screen shows a friendly illustration of a person with a book, above the heading "Save anything to read later". What alt text should the illustration have?

Exercise 8.1 30 minutes · on your own product

Alt text inventory

  1. List every image and icon in your product and marketing site (a quick DOM query like document.querySelectorAll('img, svg, [role=img]') helps).
  2. Classify each: decorative, informative, functional, text, complex.
  3. Write or fix the text alternative for each using the decision tree.
  4. Read five of them aloud in context. Cut any that repeat nearby text.
You're done when: every image has a deliberate alternative (including deliberate empty ones) and you can justify each in one line.
BeginnerCompetentStrong
Alt added to content images only.All images classified; icons in buttons named by action.Build check prevents missing alt; charts have summaries and data tables.
9

Hearing: captions, transcripts and visible sound

Taught by W3C WAI media guide, with Deaf and hard-of-hearing communities

Anything your product says with sound must also be said with sight: captions for video, transcripts for audio, and visual or haptic equivalents for alerts.

Hearing loss is common and increases with age; many people are hard of hearing rather than profoundly deaf, and some Deaf people use a sign language as their first language and read captions as a second language. Add the situational group (open-plan offices, trains, sleeping babies) and the case for visual alternatives is overwhelming. For a software product, sound appears in three places: media (video, audio, podcasts), feedback (alerts, chimes, notification sounds) and voice interfaces.

Captions done properly

Captions are synchronised text of speech plus meaningful sound ("[door slams]", "[soft piano music]"). Subtitles usually translate speech only, assuming the viewer can hear. Good captions are accurate, synchronised, complete and readable: one or two lines, high contrast, not covering important on-screen text, with speaker identification when it is not obvious. Automatic captions have improved a lot but still mangle names, jargon, accents and Indian English mixed with Hindi; correct them for anything you publish.

we're going to sink your notes ROHIT: We're going to sync your notes. [notification chime] Auto, uncorrected, low contrast Corrected, backed, speaker and sound Errors in names and jargon are the norm in raw auto-captions.
A caption is a reading experience. Give it a solid backing, keep it to two lines, identify speakers, and include sounds that matter to meaning.

Transcripts

For audio-only content (podcasts, voice notes), provide a transcript. For video, a transcript is also useful: it lets people skim, search, read at their own pace, and use a braille display. Deaf-blind users rely on text that can be sent to braille. A transcript is also great for search engines and for you, since it becomes a blog post.

Visible and tangible feedback

If a sound means something (message received, timer done, error), pair it with a visual change and, on phones, a haptic. Never make the sound the only cue. Allow sounds to be turned off and respect system mute. For voice features, offer a typed alternative: people with speech differences, strong accents, or in quiet places cannot always speak to your app.

Don't
Hold to talk
Voice only. Notes exist only as audio; no way to type, no transcript to read or search.
Do
Type…
Voice and text, with transcript. Every note is readable and searchable; the keyboard is always an option.

Do

  • Caption every video you publish, including marketing and onboarding videos.
  • Correct auto-captions for names, product terms and code.
  • Pair sounds with visual and haptic cues.
  • Offer typed input wherever you offer voice input.

Don't

  • Autoplay video with sound.
  • Burn captions into the video as the only option; users cannot resize or restyle them.
  • Use phone verification by voice call as the only option.
  • Rely on a sound to confirm a destructive action.

In the wild

  • Live CaptionAndroid 10, 2019; iOS Live Captions, 2022
    On-device captioning of any audio playing on the phone, including calls and videos without captions. Platform features help, but do not replace authored captions for your own content; they can be wrong on names and terms.
  • Sound RecognitioniOS 14, 2020
    Detects sounds like doorbells, alarms and crying babies and shows a notification. Turning sound into visual notifications is a pattern your app can apply to its own alerts.
  • YouTube captionsGoogle
    Viewers can change caption size, font, colour and background opacity. Captions as text, not pixels, let each viewer adapt them.
For the solo creator

If you make product videos, write the script first. The script becomes your captions file (WebVTT or SRT) and your transcript with almost no extra work, and your videos will be clearer because you planned them. Upload the captions file; do not rely on auto-captions.

Common mistakes

Trusting auto-captions

They look good enough at a glance.

Read them through once. Fix names and terms; that is where errors cluster and where meaning lives.

Silent videos with no text

Product demo GIFs with no narration seem safe.

They are not a problem for Deaf users, but they are for blind users: add a short text description of what the demo shows.

Check yourself

Your meditation app ends each session with a gentle bell. A Deaf user says she never knows when the session is over. What is the best fix?

Exercise 9.1 30 minutes · on your own product

Sound-off audit

  1. Mute your device and turn off vibration. Use your product for ten minutes.
  2. Note every moment you missed information that sound would have given.
  3. Unmute, turn off the screen (or close your eyes) and note what you missed that only sight gave.
  4. For each gap, design the alternative channel.
You're done when: every sound has a visual equivalent, every video has a corrected captions file, and voice features have a typed alternative.
BeginnerCompetentStrong
Sound cues listed.Every cue has a visual or haptic twin; videos captioned.Transcripts published and reused as written content.

Part two recap: connect the ideas

Recap

In Words you learned to write labels that name actions with verbs. How does that connect to this part?

Part three

Hands and minds

This part covers people who do not use a mouse or a precise finger, and people whose attention, memory or reading differs from yours. The common thread: interfaces that are predictable, forgiving and reachable by more than one kind of input.

10

Keyboard and focus: the spine of operability

Taught by W3C WAI, with Sara Soueidan and Heydon Pickering

If something works with a mouse, it must work with a keyboard. And a keyboard user must always be able to see where they are: the focus indicator is their mouse pointer.

Keyboard access is the foundation that many other assistive technologies build on. Switch devices, sip-and-puff controllers, some voice control modes and many screen-reader interactions are translated into keyboard-like "move next" and "activate" commands. People with tremor, repetitive strain injury or limited fine motor control often prefer the keyboard. Power users choose it because it is fast. If your app is fully keyboard operable with a visible focus, you have served all of them.

The keyboard contract

Users expect a small, consistent set of keys. Tab and Shift+Tab move between interactive elements. Enter activates links and buttons. Space activates buttons and toggles checkboxes. Arrow keys move within a composite widget (radio group, tabs, menu, listbox, grid). Escape closes the thing that just opened (dialog, menu, popover). Home and End jump to the first and last items in a list-like widget. Native elements already behave this way; custom ones must be taught every key.

Skip link Logo Search Library Saved Settings 123456 main Articles Books Notes 7 ← → move between tabs (roving focus) First article link 8 Tab enters the tab list once (7), then leaves it to the panel (8).
Tab between components, arrows within them. Focus order follows reading order; a composite widget like a tab list is one Tab stop, with arrow keys inside. The first stop is a skip link to main content.

Demo: div buttons versus real buttons

Click inside the pane, then press Tab repeatedly. In "Without", the toolbar is built from divs with click handlers and the one real button has its outline removed. In "With", every control is a native element with a strong focus indicator, and a skip link appears on the first Tab.

Keyboard focus
Bold
Italic
Link
Click here, then press Tab.
Without: Tab skips Bold, Italic and Link entirely (divs are not focusable), then focus lands on Publish and the title field invisibly. A keyboard user cannot format text and cannot see where they are. The log below the field shows where focus actually went.

Designing a focus indicator

Browsers draw a default focus ring, but many designs remove it with outline: none because it appears on mouse click. The modern fix is :focus-visible, which browsers apply when focus came from the keyboard (and for text inputs always), so you can style a strong indicator without it flashing on every click. A good indicator is thick enough to see (2 to 3 px or more), contrasts at least 3:1 with the colours around it, is not only a colour change of the element itself, and is not hidden by overflow or sticky elements. WCAG 2.2's AAA criterion 2.4.13 Focus Appearance gives a precise target: an outline area at least as big as a 2 CSS px perimeter, with 3:1 contrast between focused and unfocused states.

Don't
Save Share which one is focused?
Subtle tint. A tiny shade shift fails non-text contrast and is invisible in sunlight.
Don't
ring clipped by overflow: hidden
Clipped ring. The outline is cut off by the parent. Use a negative outline-offset or give the container padding.
Do
Save Share 3 px ring, 2 px offset
Obvious ring. Thick, offset, high contrast, consistent on every control. Try tabbing through this course page; every control uses one.
/* One focus style for the whole product */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
/* Keep focused things clear of sticky headers (2.4.11) */
html { scroll-padding-top: 72px; }

Focus management

When the interface changes, put focus somewhere sensible. Opening a dialog moves focus into it; closing returns focus to the button that opened it. Deleting a list item moves focus to the next item (or the list heading), not to the top of the page. After a route change in a single-page app, move focus to the new page's heading or main region, otherwise screen-reader users have no idea anything changed. Never use positive tabindex values (1, 2, 3); they create an order that fights the DOM. Use tabindex="0" to make a custom element focusable and tabindex="-1" to make something focusable only by script.

Skip links

A skip link is the first focusable element on a page, usually hidden until focused, that jumps to the main content. Without it, a keyboard user tabs through every header link on every page. In apps with a sidebar, a "Skip to editor" or "Skip to results" link saves dozens of key presses.

Do

  • Use native buttons, links and inputs.
  • Style :focus-visible with a thick, high-contrast ring, globally.
  • Return focus to the trigger when a dialog or menu closes.
  • Document your keyboard shortcuts and avoid single-letter shortcuts that can't be turned off or remapped (2.1.4).

Don't

  • Write outline: none without a replacement.
  • Use positive tabindex.
  • Create keyboard traps (a widget you can Tab into but not out of).
  • Make hover the only way to reveal actions.

In the wild

  • Linear2019 onwards
    Built keyboard-first: a command menu (Cmd-K), shortcuts for nearly every action and visible focus within lists. Keyboard operability as a brand value serves accessibility and speed at once.
  • Things 3Cultured Code, 2017
    On Mac, you can create, move, schedule and complete to-dos without the mouse, with a clear selection highlight. A calm app can be a fully keyboard-driven one.
  • GOV.UKDesign System
    Uses a distinctive yellow focus state with a dark underline, chosen to stand out on any background colour. A focus style can be bold and on-brand.
For the solo creator

Unplug your mouse (or turn off your trackpad) for the first half-hour of each Monday while you use your own product. Every time you get stuck, you have found a bug. Add one global :focus-visible rule today; it takes two minutes and fixes focus visibility across the whole app.

Common mistakes

Removing outlines globally

A CSS reset or a designer's request to "remove the blue box".

Replace, never remove. Use :focus-visible so mouse users don't see it on click.

Hover-only actions

Row actions (edit, delete) appear on mouse hover to keep lists clean.

Also show them on :focus-within, and make them reachable on touch (a "more" button or swipe with an alternative).

Focus lost after actions

The element that had focus was removed from the DOM, so focus falls back to the page body.

Before removing, decide where focus goes next and move it there.

Check yourself

You have a list of 200 notes. Each row has Open, Pin, Share and Delete buttons. Tabbing through the page takes 800 key presses. What is the better pattern?

Exercise 10.1 45 minutes · on your own product

The no-mouse pass

  1. Disable your mouse or trackpad.
  2. Complete your three main tasks with only the keyboard.
  3. For each step, record: could I reach it? Could I see focus? Did focus go somewhere sensible afterwards? Could I escape?
  4. Add a global focus-visible style and a skip link if you lack them.
You're done when: all three tasks complete by keyboard alone, with focus visible at every step.
BeginnerCompetentStrong
Problems listed.Everything reachable; focus visible; dialogs return focus.Composite widgets use arrow keys; a keyboard shortcut sheet exists and is reachable with ?.
11

Targets, gestures, switches, voice and time

Taught by W3C WAI, with Apple HIG, Material Design and Paul Fitts

People reach your interface with fingers that shake, a single switch, their voice, a head pointer, or one thumb on a moving bus. Make targets big and well spaced, give every gesture a simple alternative, and never make people race a clock.

Fitts's law, which you met in The Human Mind, says the time to hit a target grows as it gets smaller and farther away. For people with tremor, arthritis, cerebral palsy, Parkinson's, or cold hands at a bus stop, small targets are not just slower; they produce errors, and errors on destructive actions are costly. Motor accessibility is mostly about margin: bigger targets, more space, simpler gestures, more time, undo.

Target size

WCAG 2.2's 2.5.8 sets a minimum of 24 by 24 CSS pixels (or enough spacing). Platform guidance is more generous and you should follow it: Apple recommends at least 44 by 44 points, Material Design 48 by 48 dp (about 9 mm). The visible icon can be smaller than the target; extend the hit area with padding. Space destructive actions away from frequent ones.

Lab: target size and tremor
Tap or click the "Save" target. Each tap is shifted by a random amount, like a hand tremor.
"Save" sits between "Archive" and "Delete". With a small target, small gap and some tremor, a surprising share of taps hit the wrong button, and one of the neighbours destroys data. Raise size and gap until the simulated miss rate falls near zero; notice it happens around 44 px.

Gestures and dragging

Complex gestures (multi-finger swipes, pinches, path-based gestures like drawing a shape) are hard or impossible for many people, and invisible to everyone until learned. WCAG 2.5.1 Pointer Gestures requires that anything done with a multipoint or path-based gesture can also be done with a single pointer without a path (a tap or click). 2.5.7 Dragging Movements, new in 2.2, extends that to dragging: reordering a list, moving a slider, dragging a card between columns must also be possible with taps or clicks, such as "Move up" and "Move down" buttons or a "Move to…" menu. 2.5.4 Motion Actuation says shake-to-undo and tilt controls need a regular control too and must be possible to turn off.

Don't
To readReading drag is the only way
Drag only. Impossible for switch, voice and many keyboard and tremor users, and fiddly on a phone.
Do
To readReading ⋯ Move to ReadingMove to DoneMove up
Drag plus a menu. Keep dragging for those who like it; add a "Move to…" menu reachable by tap, keyboard, switch and voice.

Switch control and voice control

Switch users operate a device with one or two buttons (or a head movement, a sip-and-puff tube, a blink). iOS Switch Control and Android Switch Access scan through the interface, highlighting groups and then items, and the user presses the switch to select. Every extra focusable element adds scanning time, so clean grouping and logical order matter enormously. Elements that only appear on hover or after a timeout are often unreachable.

Voice control users speak commands: "Tap Save", "Scroll down", "Show numbers" (which overlays a number on every control). iOS Voice Control, macOS Voice Control, Android Voice Access and Windows Voice Access all match spoken words against accessible names. If your visible button says "Send" but its accessible name is "Submit message form", saying "Tap Send" fails. That is WCAG 2.5.3 Label in Name: the accessible name must contain the visible label, ideally starting with it.

Switch scanning: group, then item 1. toolbar (highlighted)2. list3. tab bar Voice control: "Show numbers" CancelSend Message 123 "Tap Send" needs "Send" in the name.
Two very different inputs, the same requirements. Logical grouping, few unnecessary stops, and accessible names that match visible labels.

Time limits

Some people read slowly, type slowly with a head pointer, or need to look something up. WCAG 2.2.1 requires that time limits can be turned off, adjusted, or extended (with a warning and at least 20 seconds to respond), unless the limit is essential (like a live auction). 2.2.2 requires that moving, blinking or auto-updating content lasting more than five seconds can be paused. In practice: don't auto-dismiss toasts that contain actions (like Undo) in three seconds; don't auto-advance carousels; warn before a session expires and let people extend it with one tap; save drafts so a timeout never loses work.

Note deletedUndo gone in 3 s: Undo unreachable Note deletedUndo stays ~10 s+, pauses on hover/focus, Undo also in Edit menu and ⌘Z
Time is an accessibility parameter. A three-second toast with an action is a race. Make actions persist somewhere else too.

Do

  • Use 44 pt / 48 dp targets on touch; at least 24 px on the web, with spacing.
  • Give every drag and multi-finger gesture a tap or menu alternative.
  • Match accessible names to visible labels.
  • Let people extend or turn off time limits; save drafts constantly.
  • Place destructive actions away from common ones and offer undo.

Don't

  • Use swipe-only actions with no visible equivalent.
  • Trigger actions on pointer-down; trigger on release so people can slide off to cancel (2.5.2).
  • Auto-advance carousels or auto-dismiss toasts with actions.
  • Rely on shake, tilt or long-press as the only way to do something.

In the wild

  • iOS Mail swipe actionsApple
    Swiping a message reveals actions, but the same actions exist as buttons in the message view and as VoiceOver custom actions on the row. A gesture can be the shortcut, never the only door.
  • Gmail "Undo Send"Google
    Gives a configurable window (5 to 30 seconds) to recall a sent email. Letting users choose the time limit is the WCAG idea in product form.
  • Voice ControliOS 13 and macOS Catalina, 2019
    Full device control by voice, including "show names" and "show numbers" overlays. Your accessible names are literally the vocabulary users speak.
For the solo creator

In SwiftUI and UIKit, expose swipe and long-press actions as accessibility custom actions (.accessibilityAction(named:)); in Compose, use customActions in semantics. It is a few lines per row and makes your gestures available to VoiceOver, Switch Control and Voice Control in one go.

Common mistakes

Tiny icon buttons in toolbars

The icon is 16 px and the button is sized to the icon.

Keep the 16 px glyph, pad the button to 44 px. Visual density and hit size are separate decisions.

Hidden names that differ from labels

Developers write "descriptive" aria-labels like "Submit the form".

Start the accessible name with the visible label: visible "Send", name "Send" or "Send message".

Session expiry that loses work

Security defaults copied from banking.

Warn before expiry, allow extension, and autosave so re-login restores state (3.3.7 Redundant Entry also applies).

Check yourself

Your reading app lets users reorder their queue by long-pressing and dragging. What is the minimum you should add?

Exercise 11.1 40 minutes · on your own product

Targets, gestures and timers inventory

  1. Measure your five smallest interactive elements (browser dev tools, or Xcode's view debugger). Note any under 44 pt / 24 px.
  2. List every gesture: swipe, drag, pinch, long-press, shake. For each, write its tap or menu alternative, or "none".
  3. List every timer: toasts, sessions, OTPs, carousels. For each, write how a slow user extends or disables it.
  4. Fix the worst item in each list.
  5. Turn on Voice Control and say "Show names". Check that every name matches its visible label.
You're done when: three inventories exist, every "none" has a planned fix, and the worst of each is fixed.
BeginnerCompetentStrong
Small targets enlarged.All gestures have alternatives; timers can be extended.Custom actions added; Voice Control tested end to end on one core task.
12

Cognitive accessibility and neurodiversity

Taught by W3C COGA Task Force, with Steve Krug and the plain-language movement

Cognitive accessibility means reducing what people must understand, remember and decide at once. It helps people with learning disabilities, dyslexia, ADHD, autism, dementia, brain injury and anxiety, and it helps every tired, distracted human using your product.

Cognitive and learning disabilities are the largest and least visible group. They vary enormously: difficulty with reading, with numbers, with short-term memory, with sustained attention, with processing speed, with unexpected change, with ambiguity. WCAG 2.x covers only part of this territory, because many cognitive needs are hard to test as pass or fail. So the W3C's Cognitive and Learning Disabilities Accessibility Task Force (COGA) published a separate guide, Making Content Usable for People with Cognitive and Learning Disabilities (2021), organised around eight objectives.

1 UnderstandFamiliar controls andicons; clear purpose 2 FindSimple navigation,clear headings, search 3 Clear contentPlain words, shortsentences, one idea each 4 Avoid mistakesForgiving input, clearerrors, undo 5 FocusNo distractions,no interruptions 6 Not rely on memoryShow, don't make themremember; no puzzles 7 Help and supportEasy to find, human,in the same place 8 AdaptPersonalise text, motion,density, reminders
COGA's eight objectives, paraphrased. Objective 6 is highlighted because it is where apps fail most: passwords, codes, multi-step flows that hide earlier answers.

Plain language

Write at a level most people can read quickly when tired: common words, short sentences, active voice, one idea per sentence, the most important thing first. This is not "dumbing down"; it is respect for attention. Everything in Words applies with extra force here. Avoid idioms and metaphors that confuse literal readers and second-language readers ("ballpark figure", "circle back"). Explain numbers ("₹499 a year, about ₹42 a month"). Use the same word for the same thing everywhere.

Don't
Authentication failure
The credentials supplied could not be validated against our records. Please ensure accuracy and reattempt, or initiate the credential recovery workflow.
Jargon and passive voice. Hard for anyone under stress; very hard for people with dyslexia or reading in a second language.
Do
That password didn't match
Check for caps lock, or reset your password. We'll email you a link.
Plain and actionable. What happened, the likely cause, and the next step, in 20 words.

Memory and predictability

Working memory holds only a few items. Every time your product asks people to remember something from a previous screen (a code, a choice, an instruction), some of them will lose it. Show what they need where they need it: keep earlier answers visible in a summary, let password managers fill fields, allow paste, offer "magic link" or passkey login as alternatives to memorised passwords (WCAG 3.3.8). Predictability matters too: WCAG 3.2.3 and 3.2.4 ask for consistent navigation and consistently named components; 3.2.6 asks for help to be in a consistent place. Unexpected changes of context, such as a form that submits when you pick a dropdown option, disorient everyone and can stop some people entirely (3.2.2).

Step 2 of 3 · Delivery Address Delivery slot Your order so far Annual plan · ₹499Edit rohit@example.comEdit Nothing to remember.
Externalise memory. A visible summary of earlier choices, a clear "step 2 of 3", and edit links mean nobody has to hold the whole flow in their head.

Attention, distraction and anxiety

For people with ADHD, distraction is not a minor annoyance; it can end the task. For anxious users, countdowns ("Offer ends in 04:59"), scarcity messages and aggressive red warnings raise stress and cause mistakes. Calm products are cognitively accessible products: one primary action per screen, no auto-playing motion, notifications that are few and useful, and reassurance at moments of risk ("You can change this later", "Nothing is charged until you confirm"). Respect prefers-reduced-motion (see Motion & Feel): parallax and large animated transitions can cause nausea for people with vestibular disorders, and flashing more than three times a second can trigger seizures (WCAG 2.3.1).

Reading differences: dyslexia

Dyslexia affects decoding written words. What helps is well established and simple: left-aligned (not justified) text, generous line spacing (around 1.5), comfortable line lengths, sans or humanist fonts with clear letter shapes, no long blocks of italics or capitals, and the ability to change font size and spacing. Specially designed "dyslexia fonts" are popular, but controlled studies have generally not found that they improve reading speed or accuracy compared with ordinary clear fonts; what matters more is spacing, size and the reader's own preference. Offer choice (as Kindle and many reading apps do) rather than one prescribed font. Text-to-speech and read-aloud support are often more helpful than any font.

Don't

NOTICE: YOUR SUBSCRIPTION WILL RENEW AUTOMATICALLY. Justified italic text with tight leading produces uneven word gaps and rivers, and readers lose their place between lines when every line looks the same.

Justified, italic, tight, capitals. Four known reading barriers together.
Do

Your plan renews on 3 March. We'll remind you a week before. You can cancel any time in Settings.

Left-aligned, spaced, short. Bold for the key fact, sentence case, line height about 1.5, short lines.

Do

  • Use plain language and explain unusual words.
  • Keep navigation, labels and help in consistent places.
  • Show progress and earlier answers in multi-step flows.
  • Prevent errors (good defaults, forgiving formats) and offer undo.
  • Let people control motion, text size, spacing and notifications.

Don't

  • Use countdown timers or fake scarcity.
  • Change context unexpectedly (auto-submit, auto-redirect).
  • Require memory tests at login (no paste, CAPTCHAs without alternatives).
  • Fill screens with competing calls to action and badges.

In the wild

  • GOV.UK "one thing per page"Government Digital Service
    Complex forms are split into pages that each ask one question, with a check-your-answers summary before submitting. Their research found this easier for users with cognitive and other disabilities and for everyone else. Lower cognitive load per screen beats fewer screens.
  • PasskeysApple, Google, Microsoft, 2022 onwards
    Sign-in with a device unlock (face, fingerprint, PIN) instead of a memorised password. Removing a memory test is a security win and a cognitive accessibility win.
  • Apple Assistive AccessiOS 17, 2023
    A simplified mode with large buttons, fewer choices and streamlined core apps, designed with people with cognitive disabilities. Sometimes the most accessible version is the one with fewer features, a lesson your calm products already lean towards.
For the solo creator

Your taste for calm, minimal products is a cognitive-accessibility advantage. Protect it: before adding a feature, ask what it adds to the memory and attention load of the screens it touches. Read your interface copy aloud once per release; anywhere you stumble, a reader with dyslexia will too.

Common mistakes

Clever microcopy

Playful wording feels on-brand.

Be playful in empty states and celebrations, literal in buttons, errors and settings.

Icons without labels

Minimalism removes text from navigation.

Label icons in navigation, at least in a tab bar. Unlabelled icons rely on memory and guesswork.

Settings that reset

Preferences stored only per session or per device.

Persist personalisation (text size, theme, reduced motion) so people set it once.

Check yourself

Your sign-up flow has a CAPTCHA that asks users to identify traffic lights in images. Which change is best for cognitive accessibility while keeping bots out?

Exercise 12.1 45 minutes · on your own product

Cognitive load walk-through

  1. Pick your sign-up or onboarding flow.
  2. For each screen, count: decisions asked, things to remember from previous screens, words on screen, competing calls to action.
  3. Rewrite every error and instruction in plain language (aim for under 20 words each).
  4. Remove one decision or one memory requirement from the flow.
  5. Check that help is in the same place on every screen.
You're done when: you have a before/after table of counts per screen and the rewritten copy in your app.
BeginnerCompetentStrong
Copy rewritten.Counts reduced; memory demands removed; help consistent.You tested the flow with someone tired, distracted or reading in a second language and fixed what they stumbled on.

Part three recap: connect the ideas

Recap

Which one design decision helps keyboard users, switch users, voice-control users, and people with cognitive disabilities all at once?

Part four

Building it and proving it

You design in code, so accessibility lives in your markup and your platform APIs. This part shows the order of preference (native first, ARIA last), the keyboard contracts of the components that most often go wrong, and a testing routine that one person can run before every release.

13

Semantic HTML first, ARIA last, native APIs always

Taught by W3C (Using ARIA), with Heydon Pickering, Apple and Google accessibility docs

Native elements and platform controls come with roles, names, states, focus and keyboard behaviour built in. ARIA only changes what assistive technology is told; it adds no behaviour. So use native first, and reach for ARIA only to fill gaps.

The W3C's Using ARIA document states the first rule of ARIA use: if you can use a native HTML element or attribute with the semantics and behaviour you need already built in, do that instead of repurposing an element and adding an ARIA role, state or property. The WAI-ARIA Authoring Practices Guide puts it more bluntly: no ARIA is better than bad ARIA. WebAIM's annual scans support this: home pages that use ARIA tend to have more detected errors, on average, than those that don't, because ARIA is so often used to patch over the wrong element.

<button> <div role="button"> Role "button"In the Tab orderActivates on EnterActivates on Spacedisabled worksSubmits formsSurvives forced colours Role "button"Add tabindex="0"Write keydown handlerWrite keyup handleraria-disabled + logicWrite form logicStyle borders yourself Circles: free. Squares: your job, and your bugs.
What you inherit versus what you must rebuild. One line of native markup replaces six pieces of custom code, each a chance to get it wrong.

The five rules of ARIA, in practice

  1. Prefer native. button, a href, input, select, textarea, details/summary, dialog, fieldset/legend, label, table, h1–h6, nav, main, ul/ol.
  2. Don't change native semantics unless you really must. Don't put role="button" on a heading; put a button inside the heading.
  3. All interactive ARIA controls must be keyboard operable. If you add role="tab", you owe the user arrow keys.
  4. Don't hide focusable elements with aria-hidden="true" or role="presentation".
  5. Every interactive element needs an accessible name.

The ARIA you will actually use most is small: aria-label and aria-labelledby (names), aria-describedby (hints and errors), aria-expanded, aria-pressed, aria-checked, aria-selected, aria-current="page" (states), aria-hidden="true" for decorative icons, aria-live or role="status" for announcements, and aria-invalid for fields in error.

Don't
<div class="btn" role="button"
     aria-label="button"
     onclick="save()">
  <i class="icon-save"></i>
</div>
<span class="lbl">Email</span>
<input placeholder="Email">
ARIA patching the wrong element. Not focusable, no keyboard, a useless name ("button, button"), and an input whose only label is a placeholder.
Do
<button type="button" onclick="save()">
  <svg aria-hidden="true">…</svg>
  Save draft
</button>

<label for="email">Email</label>
<input id="email" type="email"
       autocomplete="email">
Native and labelled. Visible text names the button; the label is linked; type and autocomplete give the right keyboard and autofill.

Native platforms: the same ideas, different APIs

On iOS and Android, standard controls are accessible by default. Custom views need you to set the same four things: role (traits), name (label), state and value, and to group or hide elements sensibly.

Image(systemName: "trash")
  .accessibilityLabel("Delete highlight")

HStack { Image(book.cover); Text(book.title); Text(book.author) }
  .accessibilityElement(children: .combine)   // one stop, not three

Text("Chapter 3").font(.headline)
  .accessibilityAddTraits(.isHeader)

Toggle("Dark mode", isOn: $dark)              // role, name, state: free

Image("divider").accessibilityHidden(true)    // decorative

row.accessibilityAction(named: "Archive") { archive(item) }

@ScaledMetric var iconSize: CGFloat = 20       // scales with Dynamic Type

Grouping: fewer, richer stops

A list row with a cover image, title, author, progress and a "more" button could be five stops for a screen reader, or one stop that says "The Shape of Design, Frank Chimero, 40 percent read" with "Archive" and "Share" as custom actions. The second is dramatically faster to use. Group static content that belongs together; keep separate only the things people act on separately.

Five stops "image" · "The Shape of Design" · "FrankChimero" · "40%" · "More, button" One stop + actions "The Shape of Design, Frank Chimero,40 percent read. Actions available." Swipe up/down: Archive, Share
Group what belongs together. In SwiftUI, .accessibilityElement(children: .combine); in Compose, mergeDescendants; on the web, a link whose text contains the title with secondary details in aria-describedby.

Do

  • Use native elements and system controls first.
  • Set the page or screen language, title and headings.
  • Use autocomplete and correct input types on forms.
  • Group related static content into one accessible element.

Don't

  • Add ARIA roles to fix the wrong element; change the element.
  • Put aria-label on non-interactive divs and spans; many screen readers ignore it there.
  • Use role="application".
  • Override names with labels that differ from visible text.

In the wild

  • Apple system controlsUIKit and SwiftUI
    Standard controls support VoiceOver, Dynamic Type, Bold Text, Increase Contrast, Switch Control and Voice Control with no extra work. Every custom control you build gives up that inheritance; make sure the custom look is worth it.
  • The HTML dialog elementSupported in all major browsers since 2022
    dialog.showModal() gives you a modal with a backdrop, focus moved inside, Escape to close and the rest of the page made inert. The platform keeps absorbing patterns you used to build by hand. Check before you build.
For the solo creator

Install a linter that knows accessibility (eslint-plugin-jsx-a11y for React, Android Lint's accessibility checks, SwiftLint's accessibility rules) and treat its warnings as errors. It is your always-on reviewer. Then make your own component library small and native-first: one Button, one TextField, one Dialog, each done right once.

Common mistakes

aria-label on everything

It feels like adding accessibility.

Use visible text as the name where possible; use aria-label only where there is no visible text (icon buttons).

Wrong element for the job

Links styled as buttons or buttons used for navigation.

Navigates somewhere? a href. Does something on this page? button. Users expect different keys and announcements.

Check yourself

You need a disclosure section ("Show advanced options") on a settings page. What is the best implementation?

Exercise 13.1 60 minutes · on your own product

Native-first refactor

  1. Search your codebase for click handlers on non-interactive elements (onClick on div or span, onTapGesture on plain views).
  2. Replace each with a native button or link, or a SwiftUI Button / Compose clickable with a role.
  3. Search for role= and aria-; for each, ask whether a native element would remove the need.
  4. Add the linter and fix its findings.
You're done when: no clickable non-interactive elements remain, and the accessibility linter runs in CI with no errors.
BeginnerCompetentStrong
Obvious div buttons replaced.All custom controls audited; linter added.Your component library documents role, name, state and keyboard behaviour for each component.
14

Component patterns: dialog, menu, tabs, combobox

Taught by WAI-ARIA Authoring Practices Guide (APG), with Scott O'Hara and Adrian Roselli

A few composite components cause most keyboard and screen-reader failures. Each has a known contract (roles, states, and which keys do what) published in the W3C's Authoring Practices Guide. Learn the contract, or better, use a well-tested implementation.

The APG is a W3C resource that documents design patterns with roles, states and keyboard interaction, plus working examples. It is guidance rather than a standard, and its examples are not production code, but it is the best shared definition of how components should behave. Below are the four you are most likely to build, with their contracts reduced to what you must remember.

Modal dialog

Delete… page behind: inert Delete "Trip ideas"? This can't be undone. Cancel Delete 12345
Focus in, focus contained, focus back. For destructive confirmations, put initial focus on the safe choice (Cancel). Title the dialog with aria-labelledby pointing at its heading.

Contract: role="dialog" (or the native <dialog> opened with showModal()), aria-modal="true", a name from its heading. On open, focus moves inside. Tab and Shift+Tab cycle within it. Escape closes. On close, focus returns to the element that opened it. The rest of the page is inert (not focusable, not read).

Menu button

Contract: a button with aria-haspopup="menu" and aria-expanded. Enter, Space or Down Arrow opens the menu and focuses the first item; Up Arrow can focus the last. Inside, arrow keys move, Home and End jump, typing a letter jumps to the matching item, Enter activates, Escape closes and returns focus to the button. Items use role="menuitem" inside role="menu". Important nuance: ARIA menus are for application-style action menus. Site navigation is not a menu; use a list of links in a nav, with a disclosure button if it collapses.

Tabs

Contract: role="tablist" containing role="tab" elements, each with aria-selected and aria-controls pointing to a role="tabpanel". Only the selected tab is in the Tab order (roving tabindex). Left and Right Arrow move between tabs; Home and End go to first and last. Tab moves from the tab list into the panel. Selection can follow focus (automatic) if panels load instantly, or wait for Enter or Space (manual) if they are slow.

Highlights Notes Bookmarks tabpanel (aria-labelledby the selected tab) ← → Home End move within the tablist Tab
One Tab stop for the whole tab list. This course's own tab components follow this pattern; try them with the keyboard.

Combobox (autocomplete)

Contract: a text input with role="combobox", aria-expanded, aria-controls pointing at a role="listbox" of role="option" items, and aria-activedescendant naming the highlighted option while focus stays in the input. Down Arrow opens and moves through options, Enter selects, Escape closes (a second Escape may clear). Announce the number of results with a polite status message ("5 suggestions"). Comboboxes are the hardest of these to get right across screen readers; if a native <select> or <datalist> will do, use it, and if not, use a well-tested library component.

ComponentNative first?Must-have keysMust-have states
Modal dialog<dialog> + showModal()Tab cycle, Escapearia-modal, name from heading; focus return
Disclosure<details>Enter, Spacearia-expanded
Menu buttonnone (or a list of buttons in a popover)Arrows, Home/End, Escape, type-aheadaria-haspopup, aria-expanded
TabsnoneArrows, Home/Endaria-selected, aria-controls, roving tabindex
Combobox<select>, <datalist>Down/Up, Enter, Escapearia-expanded, aria-activedescendant, result count
Switch<input type="checkbox" role="switch"> or a buttonSpace (and Enter for button)aria-checked or checked

Do

  • Read the APG pattern before building any composite widget.
  • Use a well-tested library (React Aria, Radix, Headless UI, or platform controls) when native is not enough.
  • Test each component with keyboard and at least one screen reader.

Don't

  • Use role="menu" for site navigation.
  • Copy APG example code into production unchanged; it is a demonstration.
  • Build a custom select just to style the arrow.

In the wild

  • React AriaAdobe
    A library of unstyled hooks and components implementing APG behaviour, tested across screen readers and input types. Buying behaviour and owning the visuals is the right split for a solo developer.
  • Raycast and Linear command menus2020s
    Command palettes are comboboxes: an input plus a filtered list navigated with arrows. The most "designed" interactions of modern apps are standard patterns underneath; follow the contract and they work for everyone.
For the solo creator

Never hand-roll a combobox or a date picker under deadline. Use a library that publishes its accessibility testing, style it to your taste, and spend your saved time on the parts of your product that are actually unique.

Common mistakes

Modal without focus return

The dialog closes and focus falls to the top of the page.

Store the trigger on open; call trigger.focus() on close. Native dialog does this for you in modern browsers.

Every tab in the Tab order

Tabs built as buttons with no roving tabindex.

Only the selected tab has tabindex="0"; others have -1; arrows move focus.

Background scroll and focus behind modals

The overlay is just a visual layer.

Make the background inert (the inert attribute, or native modal dialog).

Check yourself

You open a "Delete account" confirmation modal. Where should focus go first?

Exercise 14.1 60 minutes · on your own product

Contract check of one composite component

  1. Pick your most complex component (a modal, menu, tab set, or search with suggestions).
  2. Open its APG pattern page and write its keyboard table in your notes.
  3. Test every key in the table on your component. Mark pass or fail.
  4. Test with VoiceOver or NVDA: does it announce role, name and state changes?
  5. Fix or replace it with a tested library component.
You're done when: the component passes every row of its keyboard table and announces correctly in one screen reader.
BeginnerCompetentStrong
Keyboard table written.All keys pass; states announced.Tested in two screen readers; automated keyboard test added.
15

Testing accessibility on your own

Taught by Deque (axe), UK GDS, with WebAIM

Automated tools catch a meaningful but limited share of accessibility problems. A repeatable manual routine (keyboard, screen reader, zoom, grayscale, contrast) catches most of the rest, and testing with disabled people catches what you would never think of.

How much do automated tools find? Estimates vary with what is counted. In a 2017 experiment, the UK Government Digital Service built a page with 142 deliberate accessibility barriers and ran it through 13 automated tools; even the best found well under half of them. Deque, which makes axe, reported in 2021 that across its audits, axe-core's automated rules found about 57 percent of issues by volume, because the most common issues (like contrast) are also the most automatable. A fair summary: tools reliably find missing names, contrast failures, missing labels, invalid ARIA and some structure problems; they cannot judge whether alt text is meaningful, whether focus order makes sense, whether a flow is understandable, or whether a custom widget actually works with a keyboard.

What each layer catches (illustrative) Automated: axe, Lighthouse, lintersnames, contrast, labels, ARIA + Keyboard and screen reader passesorder, traps, meaning + Zoom, text size, grayscale, motionlayout + Testing with disabled users: real tasks, real assistive tech, surprises
Each layer is cheap; together they are thorough. Widths are illustrative, not measured. The point is that the scanner is the first layer, not the whole stack.

The solo audit routine (about 90 minutes)

  1. Automated scan, 10 minutes. Run axe DevTools or Lighthouse on each main screen of your web app; run Xcode's Accessibility Inspector audit on iOS and Google's Accessibility Scanner on Android. Fix everything they report; they are cheap wins.
  2. Keyboard pass, 15 minutes. No mouse. Tab through each main task. Check: reachable, visible focus, sensible order, no traps, Escape closes things, focus returns after dialogs, nothing hidden under sticky headers.
  3. Screen-reader pass, 25 minutes. Run the script below with VoiceOver (Mac or iPhone), TalkBack or NVDA.
  4. Zoom and text size, 10 minutes. 200% text size; 400% browser zoom or a 320 px window; iOS largest accessibility size. Look for clipping, overlap, truncation and sideways scrolling.
  5. Colour and contrast, 10 minutes. Grayscale filter on; check every status and chart. Spot-check muted text, placeholders, borders and focus rings with a contrast checker in both themes.
  6. Motion and time, 5 minutes. Turn on Reduce Motion; check that large animations calm down. Wait out every timer and toast; check you can still act.
  7. Log and prioritise, 15 minutes. Write each issue with the criterion, the user it blocks, severity (blocker, serious, minor) and the fix.

A screen-reader pass script

Use the same script every time so results are comparable between releases.

StepDo thisListen for
1. ArriveOpen the screen; let it read the title.A page or screen title that says where you are.
2. SkimNavigate by headings (rotor, H key).A logical outline; no missing or fake headings.
3. LandmarksJump by landmarks (D key in NVDA, rotor).Main, navigation, search are present and named if repeated.
4. ControlsSwipe or Tab through every control.Each has a name, the right role, and its state.
5. ImagesVisit images and icons.Meaningful alt; decoratives silent.
6. FormsFill a form with one deliberate error.Labels read on focus; error announced and linked to its field.
7. DynamicTrigger save, search, load more, a toast.Status messages announced without losing your place.
8. DialogsOpen and close a dialog and a menu.Focus moves in, is contained, returns to the trigger.
9. TaskComplete the core task with the screen curtain on.You can finish without sighted help.

Lab: a quick grayscale check

Here is the same small dashboard with and without colour. Toggle and ask: does any meaning disappear?

Grayscale check
In colour
Pro monthlyTeam annualStudent
In grayscale
Pro monthlyTeam annualStudent
Without: in grayscale the green, red and amber dots become three similar greys. Which subscription failed?

Testing with disabled people

Nothing replaces watching a screen-reader user, a switch user, or someone with a cognitive disability use your product. As a solo creator you can still do it: invite users from your support inbox who mention assistive technology, post in accessibility communities with a clear, paid offer, or use services that recruit disabled testers. Pay people for their time, as you would any expert. Give them a real task, use their own devices and settings, and stay quiet while they work. One session will teach you more than a week of reading. See Testing & Iteration for how to run sessions alone.

Do

  • Automate what you can in CI (axe-core in end-to-end tests, linters, contrast checks on tokens).
  • Run the same manual routine before every significant release.
  • Log issues with criterion, affected users and severity.
  • Pay disabled testers; treat them as experts.

Don't

  • Take a 100 Lighthouse score as proof of accessibility.
  • Test screen readers only on desktop if most users are on phones.
  • Ask a disabled friend to test for free, repeatedly.
  • Fix only what the scanner flags.

In the wild

  • axe-coreDeque, open source
    The rules engine behind many tools, including Lighthouse's accessibility audit; it can run inside Playwright, Cypress or Jest tests. Put it in your test suite so regressions fail the build.
  • Accessibility InspectorApple, ships with Xcode
    Shows the accessibility properties of any element on Mac or a connected simulator, and runs an audit for missing labels, small targets and contrast. Seeing the tree directly makes role and name bugs obvious.
  • Accessibility ScannerGoogle, Android
    An app that scans screens on a real device and suggests fixes for touch target size, contrast and labels. Run it on a cheap phone, not just your own.
For the solo creator

Schedule the 90-minute audit as a recurring calendar block before each release. Add an axe check to your end-to-end tests for your three core screens. Keep the checklist below and tick it every time; the persistent ticks show you what you did last round.

Checklist: accessibility pre-ship

Perceivable
Operable
Understandable
Robust

Common mistakes

Testing only on your best device

It is the one in your hand.

Keep a cheap Android phone for testing; TalkBack on slow hardware reveals performance and focus bugs.

Learning a screen reader on your own product first

You don't yet know what "normal" sounds like.

Spend 20 minutes using a well-made app (Apple's Settings, a GOV.UK service) with the screen reader first, then test yours.

Check yourself

You have two hours before a release. Which plan finds the most serious problems?

Exercise 15.1 90 minutes · on your own product

Your first full audit

  1. Run the seven-step routine above on your product's three core tasks.
  2. Log every issue in a11y-log.md with criterion, affected users, severity, fix.
  3. Tick the pre-ship checklist honestly.
  4. Fix all blockers. Schedule the serious issues.
  5. Update your accessibility statement from Chapter 2 with what you found.
You're done when: you have a prioritised issue log, zero known blockers, and an updated statement.
BeginnerCompetentStrong
Scan run and some manual checks.Full routine done; blockers fixed; log prioritised.Automated checks in CI and a recurring audit date in your calendar; one session with a disabled tester booked.

Part four recap: connect the ideas

Recap

In Systems & Platforms you learn to build a small design system. Where is the best place to put the accessibility knowledge from this part?

Part five

Inclusive beyond disability

Inclusion is wider than disability. People read different scripts in different directions, have names and addresses your database does not expect, use phones that cost ₹7,000 on networks that drop to 2G, are 75 years old, are holding a child, or don't fit the gender drop-down. This part covers the mismatches that come from language, place, device, age, identity and culture.

16

Languages, scripts, directions and names

Taught by W3C Internationalization, with Patrick McKenzie ("Falsehoods Programmers Believe About Names") and the Unicode CLDR

English is a short, left-to-right language with a small alphabet and simple names. Design as if it were the exception: leave room for longer text, mirror for right-to-left scripts, support every script your users write, and never assume a name or an address has a fixed shape.

Text expansion

Translated text is usually longer than English. As a rough rule, long paragraphs grow by 20 to 40 percent in languages like German, French or Hindi, and short UI labels can double or triple ("Save" becomes "Speichern"; "Add" becomes "Hinzufügen"). Some languages are shorter in characters but taller: Indic scripts like Devanagari and Tamil have marks above and below the line and need more line height; Chinese and Japanese are compact but need larger sizes to stay legible. Layouts that fit English exactly will break.

Lab: text expansion and fixed widths
Library Save Download Add to collection Settings

English: the baseline everyone designs for.

Switch languages with fixed-width buttons on: German and French labels are cut off, Hindi needs more height for its marks, Arabic flips direction. Switch to flexible buttons: they grow and wrap instead. Translations here are short UI strings for illustration.

Right-to-left layouts

Arabic, Hebrew, Persian and Urdu are read right to left. In an RTL interface the whole layout mirrors: navigation starts on the right, the back arrow points right, progress fills from right to left, list chevrons point left, and text aligns right. Some things do not mirror: phone numbers, most numerals in many contexts, media playback controls (play points right in most RTL interfaces), logos, and images of real objects like clocks. On the web, set dir="rtl" and use CSS logical properties (margin-inline-start, padding-inline-end, inset-inline-start, text-align: start) so one stylesheet works both ways. iOS and Android mirror standard layouts automatically if you use leading and trailing rather than left and right.

LTRRTL (mirrored) Library +91 98765 43210 المكتبة +91 98765 43210
Mirror the layout, not everything. Back arrow, alignment, chevrons and progress mirror. The play icon and the phone number keep their direction.
RTL: physical versus logical CSS
الإعدادات
الحساب
الإشعارات
اللغة
Without: Arabic strings (Settings, Account, Notifications, Language) dropped into an LTR layout with text-align: left. Text hugs the wrong edge, avatars and chevrons sit on the wrong side, and the back arrow points the wrong way.

Scripts, fonts and input

Choose fonts that cover the scripts your users write, or define fallbacks that do (Noto families cover most of Unicode). Test Devanagari, Tamil, Bengali and other Indic scripts for clipped marks when line height is tight. Allow mixed scripts in a single field; many Indians type Hindi in Latin letters (Hinglish) and switch scripts mid-sentence. Never restrict name fields to A to Z. Sort and search with locale-aware functions (Intl.Collator), and format numbers, dates and currency with Intl.NumberFormat and Intl.DateTimeFormat: the Indian locale groups 1,00,000 (a lakh), not 100,000.

Names and addresses

Patrick McKenzie's 2010 essay "Falsehoods Programmers Believe About Names" lists assumptions that break real people: that everyone has exactly one first name and one last name, that names don't change, that names are written in one script, that names have no spaces or punctuation, that a name field can be required to have at least two characters. Many people in India use a single given name with an initial standing for a father's name or village; many people across South and Southeast Asia have no family name at all; Spanish and Portuguese naming uses two surnames; East Asian names usually put the family name first.

Don't
Madhavan
Last name is required (letters A–Z only)
560001
Western assumptions. A required last name, an A–Z rule and a 5-digit ZIP reject a mononymous user and every Indian PIN code (6 digits).
Do
R. Madhavan
Madhavan
12, 4th Cross, near Shiva temple, Jayanagar, Bengaluru 560011
One full-name field and one free address. Ask for what you need: a full name for receipts, a short name for greetings. Let addresses include landmarks.

Do

  • Leave 30 to 50 percent extra room in labels; let buttons grow and wrap.
  • Use CSS logical properties and leading/trailing constraints from day one.
  • Use a single "full name" field unless you truly need parts.
  • Format numbers, dates and currency with locale APIs.
  • Set the language of the page and of passages in other languages (lang) so screen readers switch voices.

Don't

  • Concatenate translated strings ("You have " + n + " notes"); use message formats with plurals.
  • Put text in images.
  • Use flags to represent languages (languages cross borders).
  • Validate names or addresses against one country's pattern.

In the wild

  • Google Pay and PhonePe in India2017 onwards
    UPI payment apps offer interfaces in many Indian languages, and payments are identified by phone numbers and UPI IDs rather than Western-style names. Designing around local identifiers removes a whole class of name and address failures.
  • iOS and Android RTLApple, Google
    Both platforms mirror standard controls and navigation automatically when the system language is RTL, as long as apps use leading/trailing rather than left/right. Use the platform's direction-aware layout and most mirroring is free.
  • Unicode CLDRUnicode Consortium
    The shared database of locale data (plural rules, date formats, number grouping) that powers ICU, the JavaScript Intl API and mobile platforms. Don't hand-write locale rules; the data already exists.
For the solo creator

Even if you ship only in English, build as if you will translate: externalise strings, use plural-aware message formats, logical CSS, and Intl formatting. Then add a "pseudo-localisation" mode in development that lengthens every string by 40 percent and wraps it in brackets. You will see every layout that breaks without speaking a word of German.

Common mistakes

Hard-coded left and right

Habit from years of LTR-only CSS.

Search your stylesheet for left, right, margin-left; replace with logical properties.

First name / last name split

Database templates and payment forms copy it.

One full-name field, plus an optional "what should we call you" field.

Tight line height for all scripts

Tuned for Latin text at 1.2.

Increase line height for Indic scripts (around 1.5 to 1.7) and test with real text.

Check yourself

You are launching your reading app in Hindi. Which change is most important for layout?

Exercise 16.1 45 minutes · on your own product

Pseudo-localise and mirror

  1. Add a development flag that lengthens every UI string by 40 percent (append "·····" or duplicate vowels) and wraps it in [brackets].
  2. Walk through your main screens and screenshot every break.
  3. Set dir="rtl" on your root (or switch the simulator to an RTL language) and check what mirrors and what doesn't.
  4. Review your sign-up form against the names and addresses advice above.
You're done when: the pseudo-localised and RTL versions of your main screens have no clipped or misplaced elements, and your name field accepts "R. Madhavan" and a single name.
BeginnerCompetentStrong
Breaks identified.Breaks fixed with flexible layouts and logical properties.Pseudo-locale is part of your regular checks; strings use plural-aware formats.
17

Cheap phones, slow networks, costly data

Taught by Alex Russell (performance inequality), with Google's Android Go and the "Lite" app generation

Performance is accessibility. A product that needs a flagship phone and fast Wi-Fi excludes most of the world, including most of India, and an app that freezes is unusable with a screen reader no matter how well it is labelled.

Your development machine is probably among the fastest computers your users will ever touch your product on. Much of the world, and a large share of India's hundreds of millions of smartphone users, is on budget Android phones with modest RAM and slower processors, on mobile networks that vary from good 4G and 5G to patchy 3G and 2G in trains, basements and rural areas, often on prepaid data with daily limits. Engineer Alex Russell has written for years about this "performance inequality gap": the gap between the devices developers use and the median device, which has kept JavaScript-heavy sites slow for most people.

Time until the app is usable (illustrative) Your laptop, Wi-FiBudget phone, slow 3GSame phone, lean build 0 slongermuch longer Ship less JavaScript, smaller images, and render something useful before scripts finish.
Your experience is not your users' experience. The bars are illustrative shapes, not measurements. Measure your own with a throttled profile and a real budget phone.

What to design for

Low RAM and CPU: keep bundles small, avoid heavy animation libraries, virtualise long lists, don't keep many large images in memory. Android Go, Google's edition for phones with 2 GB of RAM or less, exists because this is a mass market. Slow and flaky networks: show useful content fast (server-rendered HTML, cached shells), make every action resilient to dropping connections (queue and retry, offline-first storage), and show honest progress. Expensive data: compress images, lazy-load, let users choose lower quality, and never auto-download large media on mobile data. Small storage: keep your install size small; people delete big apps first when storage fills.

Don't
Loading… 12 s
All or nothing. A 2 MB JavaScript bundle must download, parse and run before anything shows. On a flaky network it may never arrive.
Do
Offline · saved items
Useful at once, honest about state. Cached content renders instantly; images arrive later; the banner tells the truth about connectivity.
ConstraintDesign responseEngineering response
Slow first loadShow the most useful content first; skeletons that match the real layoutServer-render; budget JavaScript (for example, under 150 KB compressed for key pages)
Flaky connectionClear offline and syncing states; never lose typed inputOffline-first storage; queue writes; retry with backoff
Costly data"Data saver" option; ask before large downloadsResponsive images (AVIF/WebP), lazy-load, cache aggressively
Low RAMSimpler screens; fewer simultaneous heavy viewsVirtualised lists; release offscreen resources
Small storageLet users clear caches and choose what to keep offlineSmall install size; download assets on demand

Do

  • Test on a real budget Android phone and with network throttling.
  • Set a performance budget and check it in CI.
  • Design offline, syncing and error states as first-class screens.
  • Respect Android's Data Saver and iOS Low Data Mode.

Don't

  • Judge speed on your laptop with fibre.
  • Autoplay video on mobile data.
  • Throw away a typed form because a request failed.
  • Ship a 100 MB app for a notes tool.

In the wild

  • Facebook LiteMeta, 2015
    A small Android app built for 2G networks and low-end phones, which became very popular in India and other markets. A deliberately light version can reach far more people than the flagship.
  • Flipkart LiteFlipkart, 2015
    An early progressive web app with offline support and fast loading on slow networks, widely cited as a pioneering PWA. The web can feel app-like on modest hardware when it is built lean.
  • YouTube GoGoogle, 2017 to 2022
    Showed the data size of each video quality before playing and allowed offline saving; discontinued in 2022 as the main app absorbed improvements for low-end devices. Showing data cost before acting respects users who pay per megabyte.
For the solo creator

Buy the cheapest current Android phone you can find and make it your second test device. Use it on mobile data for a day. Then set two numbers you will not cross: a JavaScript budget and a time-to-useful-content on that phone. Small, fast products are also calmer products.

Common mistakes

Spinner-first architecture

Client-side rendering everything is the default in many frameworks.

Render meaningful HTML on the server or from cache; hydrate progressively.

Losing work on failure

Requests assume a stable connection.

Save drafts locally before sending; show "Will send when online".

Check yourself

A user in a small town says your app "never opens". Analytics show many sessions end before the first screen renders. What is the most likely fix?

Exercise 17.1 45 minutes · on your own product

The budget-phone day

  1. Throttle your browser to "Slow 3G" and 4× CPU slowdown, or use a real budget phone on mobile data.
  2. Time how long until your main screen is useful, cold and warm.
  3. Turn on airplane mode mid-task. Note what breaks or loses data.
  4. Write a performance budget and three changes that would meet it.
You're done when: you have measured times, an offline-failure list, and a written budget with a plan.
BeginnerCompetentStrong
Measured once on throttled desktop.Measured on a real budget phone; offline failures fixed.Budget enforced in CI; offline-first storage for user input.
18

Age, situation, identity, culture and time

Taught by Kat Holmes, with W3C WAI (older users) and Sara Wachter-Boettcher (Technically Wrong)

Inclusion means noticing the defaults that quietly assume one kind of person: young, alone, at a desk, in one time zone, with a gender that fits two boxes, and a culture where red means danger and Sunday starts the week.

Older adults

Ageing brings several changes at once: reduced near focus and contrast sensitivity, slower reaction and less precise fine motor control, some hearing loss, and often less familiarity with newer interaction conventions (hidden gestures, icon-only navigation). None of these are dramatic alone; together they make many apps quietly hostile. The fixes are the ones in this guide: larger default text with scaling, strong contrast, big targets, visible labels, no hidden gestures, undo, and patience in time limits. Older adults are also often targets of fraud, so clear, consistent security messaging matters.

Situational limits

easystretchhard One hand on a bus railPrimary actions within thumb reach Bright sunlightHigh contrast, no faint text Noisy place, sleeping babyCaptions, silent visual feedback Walking, gloves, cold handsBig targets, forgiving taps, undo
The thumb zone and its friends. One-handed reach on a tall phone favours the bottom of the screen; that is why many modern apps put primary navigation and search there.

Gender and identity in forms

First ask whether you need to know at all. Most products don't need gender. If you do (for example, for medical or legal reasons), explain why, make it optional where possible, offer more than two options, and allow people to self-describe. Ask for pronouns or a form of address only if you use them. Titles (Mr, Ms, Dr) are often unnecessary. Let people change their name and email without support tickets; names change for marriage, transition, safety and many other reasons. Never show deadnames in old receipts or shared histories once someone has updated their profile.

Don't
Mr ▾
○ Male  ○ Female
MM/DD/YYYY
Required, binary, unexplained. Three questions the product doesn't need, one with only two options, and a US date format.
Do
Rohit
○ Yes  ○ No
Ask only what you use, and say why. The age gate asks the actual question rather than a full birth date.

Culture, colour and symbols

Colours and symbols carry different meanings in different places. In many Western contexts white is associated with weddings; in parts of India and East Asia it is associated with mourning. Red signals danger or loss in Western finance apps, but in Chinese stock markets red often marks prices going up. A thumbs-up, an owl, a number or a hand gesture can be friendly in one culture and rude or unlucky in another. You cannot learn every meaning; you can avoid relying on colour or symbol alone (Chapter 6 again), use words with icons, and check key symbols with people from your target markets.

Time, dates and calendars

Your users live in different time zones (India uses a single +5:30 zone, which surprises software that assumes whole-hour offsets), start their weeks on different days (Monday in much of Europe and India, Sunday in the US, Saturday in parts of the Middle East), write dates in different orders (03/04 is 3 April in India and 4 March in the US), and some use other calendars alongside the Gregorian one (Islamic, Hebrew, Indian national, Chinese lunar, Vikram Samvat for festivals). Show dates unambiguously ("3 Apr 2026", or relative "Tomorrow, 9:00"), store times in UTC with the user's zone, use locale formatting, and let users choose their first day of the week.

03/04/2026 India, UK: 3 April US: March 4 3 Apr 2026 Clear everywhere, or use locale formatting.
Ambiguous dates cause real mistakes. Missed flights and wrong deadlines start here. Spell out the month or use locale-aware formatting.

Do

  • Place primary actions within thumb reach on phones.
  • Ask only for personal data you use, and say why.
  • Let people edit names, emails and pronouns themselves.
  • Use locale formatting for dates and times; support half-hour time zones.
  • Pair colours and symbols with words.

Don't

  • Require gender, title or full birth date by default.
  • Assume the week starts on Sunday.
  • Use culturally loaded imagery without checking.
  • Design only for a young, expert, two-handed user.

In the wild

  • Facebook custom genderMeta, 2014
    Expanded beyond two gender options and added a choice of pronouns for how the product refers to you. The form field is a statement about who the product is for.
  • Calendar appsApple, Google
    Let users choose the first day of the week and show alternate calendars (such as Hijri, Hebrew or Chinese) alongside Gregorian dates. Small settings respect large differences.
  • Bottom navigation and searchMany apps, 2020s
    iOS Safari's move of the address bar to the bottom (iOS 15, 2021) and bottom tab bars in most apps respond to one-handed use on tall phones. Physical reach is a design constraint, not a preference.
For the solo creator

Audit your sign-up and profile forms in ten minutes: delete every field you don't use, make the rest optional where you can, and add a one-line "why we ask" to anything sensitive. It reduces abandonment, reduces stored personal data (a privacy win, see Honest & Calm) and includes more people.

Common mistakes

Collecting data "just in case"

It feels free to ask.

Every field costs completion, trust and security. Ask when you need it, not at sign-up.

Timestamps without zones

Everything was tested in one city.

Store UTC; display in the viewer's zone; say "your time" when sharing across zones.

Check yourself

Your habit app sends a daily reminder "at 9:00". A user who travels from Mumbai to Berlin says it now arrives at midnight. What design decision fixes this?

Exercise 18.1 40 minutes · on your own product

The assumptions audit

  1. List every place your product asks for or shows personal data, dates, times, colours with meaning, or symbols.
  2. For each, write the hidden assumption ("week starts Sunday", "two genders", "red = bad", "user is in one time zone").
  3. Use your product one-handed on a bus or walking for ten minutes; note what you couldn't reach.
  4. Fix three assumptions.
You're done when: you have an assumptions list and three fixes shipped or scheduled.
BeginnerCompetentStrong
Assumptions listed.Three fixed, including one form field removed.Locale-aware formatting everywhere; a one-handed pass is part of your release routine.

Part five recap: connect the ideas

Recap

Look back to Chapter 1's persona spectrum. Which statement best ties this part to it?

Wrap-up

Accessibility is not a separate discipline bolted onto design. It is design done with a wider picture of who is on the other side of the screen. You now know the mechanism (the accessibility tree, contrast, reflow, focus), the standard (WCAG 2.2 AA and its key numbers), the methods (native first, APG contracts, a 90-minute audit), and the wider frame (language, device, age, identity). The rest is repetition until it becomes taste.

Ten things to remember

  1. Disability is a mismatch between a person and a design. You make mismatches, so you can remove them. Solve for one, extend to many.
  2. WCAG 2.2 AA is the yardstick most laws point to. Memorise the numbers: 4.5:1, 3:1, 200%, 320 px, 24 px, 20 seconds.
  3. Contrast: body text 4.5:1, large text and UI parts 3:1. Calm comes from restraint, not faint text. Use APCA as a second opinion, not a standard.
  4. Never let colour carry meaning alone. Add a word, a shape, a pattern or a position.
  5. Screen readers read the accessibility tree: role, name, state, order. Visual hierarchy must exist in code as headings and landmarks.
  6. Alt text does the image's job in context. Decorative images get empty alt.
  7. Everything works by keyboard, focus is always visible, and focus goes somewhere sensible after every change.
  8. Big targets, gesture alternatives, matching labels for voice control, and no races against the clock.
  9. Native first, ARIA last. Learn the APG contracts for dialog, menu, tabs and combobox, or use a tested library.
  10. Test in layers: scan, keyboard, screen reader, zoom, grayscale, motion, and real disabled users. And design for languages, cheap phones, slow networks, older users and different lives.

Self-assessment: I can…

Practice assignment for the next two weeks

The goal is to turn this guide into a habit and a measurably more accessible product.

  1. Days 1 to 2: baseline. Run the full 90-minute audit (Exercise 15.1). Publish or update your accessibility statement.
  2. Days 3 to 4: tokens and focus. Fix contrast at the token level in both themes and automate the check. Add a global :focus-visible style, a skip link, and scroll-padding for sticky headers.
  3. Days 5 to 6: names and structure. Replace every clickable non-interactive element. Add names to every icon button, real headings and landmarks to every screen. Add the accessibility linter to CI.
  4. Days 7 to 8: input alternatives. Give every gesture a tap alternative and custom action; enlarge small targets; fix timers and toasts.
  5. Days 9 to 10: text and layout. Fix every break at 200% text and 320 px; add large-text and narrow previews to your daily setup; pseudo-localise once.
  6. Days 11 to 12: words and memory. Rewrite errors and instructions in plain language; remove one memory demand from sign-in or onboarding (paste, passkeys, magic links).
  7. Days 13 to 14: real people. Book one paid session with a screen-reader user or another disabled tester. Re-run the audit and compare your issue log to day 1.

Reflection

At the end of the two weeks, write a paragraph in your design journal: which change surprised you most, which one made the product better for you, and which group of users you had not been thinking about before. Then put a recurring 90-minute audit on your calendar before every release.

Reading list

  • Mismatch: How Inclusion Shapes Design
    Kat Holmes, MIT Press, 2018 · The best short argument for inclusive design as a creative method, with the persona spectrum and many product stories.
  • Inclusive Design Toolkit
    Microsoft, 2016 · Free; the source of the permanent, temporary, situational framing. Read it in an hour.
  • Web Content Accessibility Guidelines 2.2, with the "Understanding" documents
    W3C, 2023 · The standard itself. The Understanding pages explain intent and edge cases better than any summary.
  • WAI-ARIA Authoring Practices Guide
    W3C · The keyboard and role contracts for every common widget, with working examples. Your reference before building any composite component.
  • Inclusive Design Patterns
    Heydon Pickering, Smashing, 2016 (and his Inclusive Components site) · Component-by-component, semantic-first thinking from a designer who codes, like you.
  • A Web for Everyone
    Sarah Horton and Whitney Quesenbery, Rosenfeld Media, 2014 · Accessibility through personas and UX practice, not checklists.
  • Accessibility for Everyone
    Laura Kalbag, A Book Apart, 2017 · A short, friendly overview for designers and developers.
  • Form Design Patterns
    Adam Silver, Smashing, 2018 · Accessible, inclusive forms in depth, from someone who worked on GOV.UK.
  • Making Content Usable for People with Cognitive and Learning Disabilities
    W3C COGA Task Force, 2021 · The eight objectives and design patterns for cognitive accessibility that WCAG cannot fully test.
  • Falsehoods Programmers Believe About Names
    Patrick McKenzie, 2010 · A short essay that will change every sign-up form you design.
  • Technically Wrong
    Sara Wachter-Boettcher, W. W. Norton, 2017 · How biased defaults in forms, algorithms and copy exclude people, with real cases.
  • The Curb-Cut Effect
    Angela Glover Blackwell, Stanford Social Innovation Review, 2017 · The essay behind the idea that designing for one group benefits everyone.
  • The WebAIM Million and WebAIM Screen Reader User Survey
    WebAIM, annual · Real data on what fails most often and how screen-reader users actually navigate.

Next: put numbers on screens in Information & Data, where accessible charts and tables build on Chapters 6 and 8, or jump to Testing & Iteration to plan your first session with a disabled tester.