Learn

Accessibility for Designers

Good accessibility starts in the design phase, not after handoff. This section covers the visual decisions that determine whether your product works for everyone - from focus rings to touch targets to motion. No code required.

Focus Indicators

When a user navigates with a keyboard or switch device, they rely on a visible focus ring to know which element is active. Many designs suppress the browser default without replacing it - leaving keyboard users with no visual cue at all.

The WCAG Requirements

WCAG 2.4.7 (Level AA)

Focus indicators must be visible

WCAG 2.4.11 (Level AA, WCAG 2.2)

Focus appearance - minimum 2px outline, 3:1 contrast ratio against adjacent colors

WCAG 2.4.12 (Level AAA, WCAG 2.2)

Enhanced focus appearance

See the difference

Tab through each button below. Example 1 is intentionally broken to show what keyboard users experience when focus styles are removed.

Example 1

Result: Fails WCAG 2.4.7

No focus ring - keyboard users are lost

Tab here to see focus disappear (intentional bad pattern).

Example 2

Result: Passes but not recommended

Browser default - visible but inconsistent across browsers

Tab here to see the browser default outline.

Example 3

Result: Passes WCAG 2.4.7 and 2.4.11

Custom focus ring - consistent, high contrast, on-brand

Tab here to see a 2px brand-color ring with offset.

What to hand off to your developer

Minimum focus ring spec:

  • outline: 2px solid [your brand color]
  • outline-offset: 2px
  • Contrast ratio: at least 3:1 against adjacent background

Never hand off:

outline: none without a replacement focus style

Check tool:

Use the WebAIM Contrast Checker (opens in a new tab) to verify your focus ring color.

Touch Target Sizing

Tap targets that are too small cause errors - especially for users with motor impairments, tremors, or arthritis. A target that looks fine on a desktop mockup can be nearly impossible to hit accurately on a phone.

The WCAG Requirements

WCAG 2.5.5 (Level AAA)

Touch targets must be at least 44x44 CSS pixels

WCAG 2.5.8 (Level AA, WCAG 2.2)

Touch targets must be at least 24x24 CSS pixels, OR have sufficient spacing so the total activation area reaches 24x24

WCAG 2.5.8 is the AA requirement. Design to 44x44px minimum to meet AAA and give users the most comfortable experience.

See the difference

Click each square to feel the size difference. Tab to each target to confirm focus is visible on all three.

16 × 16 px

Click the square to try it

Target 1

Result: Fails WCAG 2.5.8

16x16px - common for icon buttons. Fails both 2.5.5 and 2.5.8

24 × 24 px

Click the square to try it

Target 2

Result: Passes WCAG 2.5.8 (AA)

24x24px - minimum AA requirement under WCAG 2.2

44 × 44 px

Click the square to try it

Target 3

Result: Passes WCAG 2.5.5 (AAA)

44x44px - recommended minimum. Passes AAA

What to hand off to your developer

Minimum sizes:

  • Icon buttons: 44x44px touch target (even if the icon is smaller)
  • Text links inline: ensure 24px line height minimum
  • Form inputs: 44px height minimum

How to achieve this without making everything huge:

Use padding to extend the clickable area beyond the visible element. Example: a 16x16px icon can have 14px padding on all sides = 44x44px tap area.

In Figma:

Create a 44x44px transparent hit area layer on top of small icon buttons. Label it “Touch target” in your handoff notes.

Color Contrast

Low contrast text is one of the most common WCAG failures - and one of the easiest to prevent at the design stage. It affects users with low vision, users in bright sunlight, and anyone on a lower-quality screen.

The WCAG Requirements

WCAG 1.4.3 (Level AA)

Normal text must have 4.5:1 contrast ratio against background

WCAG 1.4.3 (Level AA)

Large text (18px+ regular or 14px+ bold) needs 3:1

WCAG 1.4.11 (Level AA)

UI components and icons need 3:1 against adjacent colors

WCAG 1.4.6 (Level AAA)

Enhanced contrast - 7:1 for normal text, 4.5:1 for large text

Text contrast examples

This button label fails contrast

Example 1

Result: 2.5:1 - Fails 1.4.3

#9CA3AF on #FFFFFF: 2.54:1

This label just barely passes

Example 2

Result: 4.6:1 - Technically passes, but risky

#6B7280 on #FFFFFF: 4.83:1

This label passes comfortably

Example 3

Result: 10:1 - Passes AA and AAA

#374151 on #FFFFFF: 10.31:1

Example 4: UI component (icon/border)

Result: 1.6:1 - Input border fails WCAG 1.4.11

#D1D5DB on #FFFFFF: 1.47:1

Result: 4.6:1 - Input border passes WCAG 1.4.11

#6B7280 on #FFFFFF: 4.83:1

Quick contrast check

Pick text and background colors to see the WCAG contrast ratio and pass/fail results update live.

4.83:1contrast ratio

  • AA normal text (4.5:1)Result: Pass
  • AA large text (3:1)Result: Pass
  • UI components (3:1)Result: Pass

What to hand off to your developer

Check every text/background color pair in your design for:

  • Body text: 4.5:1 minimum
  • Headings (18px+ or 14px+ bold): 3:1 minimum
  • Placeholder text: 4.5:1 (it is real text, not decoration)
  • Disabled states: exempt from contrast requirements
  • Logos and decorative elements: exempt

Tools to use in Figma:

  • Figma's built-in contrast checker (Inspect panel)
  • Stark plugin (free tier checks individual elements)
  • Colour Contrast Analyser by TPGi (desktop app, free)

Spacing and Readability

Tight spacing makes content harder to read for everyone - and for users with dyslexia, low vision, or cognitive disabilities, it can make a page unusable. WCAG 1.4.12 requires that users can override spacing without content breaking.

The WCAG Requirements

WCAG 1.4.12 (Level AA)

Text spacing - content must not be lost when these are overridden: line height 1.5x font size, letter spacing 0.12x font size, word spacing 0.16x font size, paragraph spacing 2x font size

WCAG 1.4.8 (Level AAA)

Line width no more than 80 characters, line spacing at least 1.5x, paragraph spacing at least 1.5x line spacing

1.4.12 is the AA requirement you must meet. Design to these values by default and your layouts will naturally pass.

See the difference

Use the toggle to compare cramped and comfortable spacing on the same paragraph. Tab to the button and press Enter or Space to switch.

Accessible typography gives readers room to breathe. When line height, letter spacing, and line length work together, people can follow text without losing their place. Dense layouts may look efficient in a mockup, but they increase fatigue for users with dyslexia, low vision, or cognitive disabilities. Generous defaults help everyone read faster with less effort.

Showing: cramped version

Result: Does not meet recommended spacing

Cramped spacing: harder to track lines, tiring to read

What to hand off to your developer

Minimum recommended text defaults:

  • Line height: 1.5 for body text (1.2 for headings is acceptable)
  • Letter spacing: 0 to 0.05em for body (avoid negative letter spacing)
  • Max line length: 60-80 characters (use max-width: 65ch in CSS)
  • Paragraph spacing: at least as large as line height

What to avoid:

  • Fixed pixel line heights that break when users zoom
  • Justified text (creates uneven word spacing)
  • All-caps body text (reduces readability for dyslexic users)

Color as the Only Differentiator

Using color alone to communicate information is one of the most common design-phase accessibility failures. Approximately 8% of men and 0.5% of women have color vision deficiency - they may not be able to distinguish red from green at all. This affects form errors, chart legends, status indicators, and more.

The WCAG Requirement

WCAG 1.4.1 (Level A)

Color must not be the only means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.

This is a Level A requirement - the baseline. There is no acceptable reason to fail it.

Form error example

Toggle between bad and good error treatment. Tab to the toggle and press Enter or Space to switch.

This field is required

Showing: bad pattern (color only)

Result: Fails WCAG 1.4.1

Color only - red border and red text. A colorblind user may not notice

Status badge example

Compare color-only status dots with badges that pair color and text labels.

Three status indicators shown as colored circles only, with no text labels.

Version 1: Bad (color only)

Result: Fails WCAG 1.4.1

Status indicators using color only

  • Active
  • Pending
  • Error

Version 2: Good (color + text)

Result: Passes WCAG 1.4.1

Status indicators using color and text

What to hand off to your developer

For every place color communicates meaning, add at least one of:

  • Text label (most reliable)
  • Icon with accessible label
  • Pattern or shape difference
  • Bold or italic weight difference

Common places this is missed:

  • Form validation (red border alone)
  • Status badges (green/yellow/red dots)
  • Chart legends (colored lines without labels)
  • Required field indicators (red asterisk alone)
  • Link underlines removed (color is then the only differentiator)

For links specifically:

If you remove the underline, links must have 3:1 contrast against surrounding body text AND a non-color hover/focus indicator.

Animation and Motion

Animation can enhance an experience - but for users with vestibular disorders, epilepsy, or motion sensitivity, it can cause dizziness, nausea, or seizures. The fix is not to remove all animation. It is to give users control.

The WCAG Requirements

WCAG 2.3.1 (Level A)

No content flashes more than 3 times per second

WCAG 2.3.3 (Level AAA)

Animation from interactions can be disabled

Best practice

Respect prefers-reduced-motion OS setting

2.3.1 is Level A - never flash content. prefers-reduced-motion is not required by WCAG AA but is expected by users and strongly recommended.

Live motion example

Choose a motion style below to preview the card.

In real implementations, this switch happens automatically via the prefers-reduced-motion CSS media query - users never need to choose manually. The buttons here are just to show you both experiences.

Designer decision guide

Does your design include animation?Nothing to doFlashes more than 3× per second?Remove itFails WCAG 2.3.1Does it play automatically?Add pause controlRequired by WCAG 2.2.2Triggered by user interaction?ReconsiderIs it necessary?Have a reduced-motion version?Add oneBest practiceYou're good to goNoYesYesNoYesNoNoYesNoYes

Legend: blue means a question to answer, red means a fix is required, amber means action needed, teal means you are done.

What to hand off to your developer

For every animation in your design, specify:

  • Full motion version: [describe the animation]
  • Reduced motion version: [instant appearance, or no animation]

CSS media query your developer will use:

@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none;
    transition: none;
  }
}

Never design:

  • Flashing or strobing effects (no exceptions)
  • Parallax scrolling without a reduced-motion alternative
  • Auto-playing carousels without pause controls

Component Specs for Designers

The six principles above apply to every component you design. This section shows what those principles look like in practice: the specific decisions to make and annotate before handoff, grouped by component type. Each one links to the playground pattern your developer will implement.

Forms and Input

  • Form validation

    What to design

    • Label above every input, never placeholder-only
    • Error state: red border + warning icon + error text (never color alone)
    • Required fields marked with an asterisk and a legend explaining it
    • Error message positioned directly below the field it describes

    What to annotate

    Tell your developer: which fields are required, what the error messages say, and that errors must be announced to screen readers on submit.

    See it in the playground →

  • Date picker

    What to design

    • A visible text input alongside the calendar trigger button
    • Calendar trigger button must have a label ("Choose date"), not just an icon
    • Selected date shown in both the input and the calendar
    • Keyboard navigation hint visible on first open ("Use arrow keys to navigate")

    What to annotate

    Tell your developer: the date format expected, whether past dates are disabled, and that the calendar must be keyboard navigable.

    See it in the playground →

  • Radio and checkbox

    What to design

    • Visible label for every radio and checkbox: never icon-only
    • Group label (fieldset legend) that names what the group is for
    • Selected state uses shape change, not color alone
    • Touch target minimum 44x44px including the label area

    What to annotate

    Tell your developer: the group label text, which option is selected by default, and whether any options are mutually exclusive.

    See it in the playground →

  • Toast/alert

    What to design

    • Always include a text label: never icon or color only
    • Dismiss button on any toast that does not auto-dismiss
    • Auto-dismissing toasts stay visible for at least 5 seconds
    • Position consistently (top-right or bottom-center: pick one)

    What to annotate

    Tell your developer: the exact message text, whether it auto-dismisses, and that it must be announced to screen readers without stealing focus.

    See it in the playground →

  • Skeleton/loading

    What to design

    • Skeleton shapes should roughly match the content they replace
    • Include a visible or screen-reader-only loading label ("Loading...")
    • Do not use a spinner alone: pair it with text
    • Avoid flashing or pulsing faster than 3 times per second

    What to annotate

    Tell your developer: that a loading announcement must be made to screen readers and that skeleton animation must respect prefers-reduced-motion.

    See it in the playground →

Overlays and Feedback

  • Modal/dialog

    What to design

    • Visible close button in the top-right corner, minimum 44x44px
    • Dialog title as visible text at the top of the modal
    • Backdrop should not be the only way to close: provide a button too
    • Design for keyboard: the first focusable element receives focus on open

    What to annotate

    Tell your developer: which element receives focus when the modal opens, that Tab must stay inside the modal while it is open, and that Escape must close it and return focus to the trigger.

    See it in the playground →

  • Alert dialog

    What to design

    • Used for destructive or irreversible actions only (delete, sign out)
    • Must have at least two buttons: confirm and cancel
    • Confirm button should be visually distinct (red for destructive actions)
    • Title and body text must be visible: no icon-only alerts

    What to annotate

    Tell your developer: that this is a blocking dialog requiring user response, that focus must go to the cancel button by default (not the destructive action), and that background content must be inert.

    See it in the playground →

  • Tooltip

    What to design

    • Appears on both hover and keyboard focus, not hover only
    • Text label only: no interactive content inside a tooltip
    • Stays visible long enough to read (do not dismiss on mouse movement)
    • Position so it does not cover the element it describes

    What to annotate

    Tell your developer: the exact tooltip text for every instance, that it must appear on focus not just hover, and that it must not contain links or buttons.

    See it in the playground →

Navigation and Layout

  • Dropdown menu

    What to design

    • Trigger must look like a button, not a styled div or text link
    • Show open/closed state visually (chevron that rotates, or +/-)
    • All states: default, hover, focus, open, disabled
    • Touch target for each menu item minimum 44px height

    What to annotate

    Tell your developer: that the trigger must be a real button element, that arrow keys must navigate the options, and that Escape must close the menu and return focus to the trigger.

    See it in the playground →

  • Navigation

    What to design

    • Skip link as the first element on every page (hidden until focused)
    • Active page indicated by more than color alone (underline, bold, or shape)
    • Mobile nav accessible without a mouse (hamburger must be keyboard operable)
    • Touch targets for all nav items minimum 44x44px

    What to annotate

    Tell your developer: which page is active on each view, that the skip link must jump to the main content area, and that the mobile menu must trap focus when open.

    See it in the playground →

  • Breadcrumb

    What to design

    • Current page shown as text, not a link (you are already here)
    • Separator between items is decorative: do not rely on it for meaning
    • Show the full path from home to current page
    • Wrap gracefully on small screens: do not truncate the current page

    What to annotate

    Tell your developer: that the current page item must be marked aria-current="page" and that the breadcrumb must be wrapped in a nav element with a label.

    See it in the playground →

  • Tabs

    What to design

    • Active tab uses underline, border, or shape change, not color alone
    • Enough contrast between selected and unselected tab states (3:1 minimum)
    • Tab panel content is immediately below the tab row
    • Touch target for each tab minimum 44px height

    What to annotate

    Tell your developer: which tab is active by default, that arrow keys must move between tabs, and that Tab must enter the panel content (not move to the next tab).

    See it in the playground →

  • Accordion

    What to design

    • Trigger must look like a button: include a chevron or +/- indicator
    • Indicator changes visually when section is open vs closed
    • Open state uses more than color to show it is expanded
    • Touch target for each trigger minimum 44px height

    What to annotate

    Tell your developer: that the trigger must be a real button element, that aria-expanded must update on open/close, and whether multiple sections can be open at once.

    See it in the playground →

  • Pagination

    What to design

    • Current page indicated by more than color alone (border, bold, or shape)
    • Previous and Next buttons always visible, disabled when at the boundary
    • Each page number is a real link or button, not styled text
    • Touch targets minimum 44x44px for all page controls

    What to annotate

    Tell your developer: that the current page must be marked aria-current="page", that disabled buttons must still be focusable with a disabled label, and that the pagination must be wrapped in a nav element with a label.

    See it in the playground →

  • Carousel

    What to design

    • Play/pause button visible and accessible at all times
    • Previous and Next controls labeled with text, not arrows only
    • Auto-play off by default, or pauses on hover and focus
    • Current slide position shown as text ("Slide 2 of 5")

    What to annotate

    Tell your developer: that auto-play must pause on hover and focus, that each slide must have a heading or label, that controls must be keyboard operable, and that animation must respect prefers-reduced-motion.

    See it in the playground →

Content and Controls

  • Icon button

    What to design

    • Every icon-only button must have a text label specified in the design
    • Label does not need to be visible but must be in the handoff notes
    • Touch target minimum 44x44px even when the icon is smaller
    • Tooltip showing the label appears on hover and focus

    What to annotate

    Tell your developer: the exact label text for every icon button, that aria-label must match that text exactly, and that the icon itself must be hidden from screen readers.

    See it in the playground →

  • Image alt text

    What to design

    • For every image, specify in handoff: is it informative or decorative?
    • Informative images: write the alt text in your design notes
    • Decorative images: mark them explicitly as decorative in notes
    • Linked images: alt text must describe the destination, not the image

    What to annotate

    Tell your developer: the exact alt text for every informative image, which images are decorative (alt=""), and that linked images need alt text describing where the link goes.

    See it in the playground →

  • Color contrast

    What to design

    • Check every text/background pair before finalising the design
    • Body text: 4.5:1 minimum against its background
    • Large text (18px+ regular or 14px+ bold): 3:1 minimum
    • UI component borders and icons: 3:1 against adjacent background

    What to annotate

    Tell your developer: the exact hex values for every color pair used, and flag any combinations that are close to the minimum ratio so they can verify in code.

    See it in the playground →

  • Data table

    What to design

    • Every column must have a clear visible header label
    • Sort direction shown with text or icon plus text, not arrow alone
    • Row hover state uses more than color to indicate selection
    • Mobile: specify whether the table scrolls horizontally or stacks

    What to annotate

    Tell your developer: the column header labels, which columns are sortable, the caption (title) of the table, and whether any rows are selectable.

    See it in the playground →

  • Progress indicator

    What to design

    • Always include a text label showing current progress ("Step 2 of 4" or "Loading: 60%"): never a visual bar alone
    • Color change alone is not enough to show progress
    • For step indicators, show which step is current and which are complete
    • Touch targets for any interactive step indicators minimum 44x44px

    What to annotate

    Tell your developer: that progress must be announced to screen readers as it updates, the exact label format to use, and whether the indicator is a progress bar or a step tracker.

    See it in the playground →

WHAT'S NEXT

Ready to see it in practice?

You've seen the principles and the component specs. The playground shows what breaks when these specs are ignored and gives developers the accessible code to fix it.

The playground shows how each of these components maps to real broken and accessible UI. Pick a pattern, see who is affected, and copy the accessible code.

Back to top