Accessibility pattern · Interaction and motion

Target size

Every target needs a 24 by 24 px hit area, or enough room that a 24 px circle on its center touches nothing else; 44 px is the AAA goal. The fix rarely means bigger icons: padding grows the button around the same icon, and an absolutely positioned ::after grows the hit area without moving anything.

WCAG criteria
5
Keyboard rules
4
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

Targets

Free delivery on orders over ₹999.

Shop now

Write a review

Handloom cotton saree, indigo

Soft handloom cotton, and the indigo is exactly as shown. The pallu could be a little longer.

Reviews follow our community guidelines and privacy notice.

Target check

Pass 0 Fail 0 Exempt 0

Counts are for AA: 24 px, or spaced (2.5.8). AAA asks 44 px (2.5.5). On the overlay: a circle badge passes, a square fails, a dotted box is an exempt link in a sentence.

#Target and sizeAA 24 pxAAA 44 px

The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

Keyboard

Keys it answers to

Every action works without a pointer.

KeyWhat it does
Tab or ShiftTabMoves between the controls, the toolbar (one stop), the links and the buttons.
Arrow Right or Arrow LeftIn the formatting toolbar, moves to the next or previous button; in the Targets group, switches between As drawn and Fixed.
Home or EndIn the toolbar, moves to the first or last button.
Space or EnterPresses the focused button: a format, Show hit areas, Post review or Dismiss the offer. Enter follows a link.

Screen readers

What it announces

Written from the roles, names and states in the markup.

WhenExpected announcement
Focus reaches the toolbarFormatting, toolbar. Bold, toggle button, not pressed
Show hit areas is pressedShow hit areas, toggle button, pressed. Hit areas shown
Fixed is chosenFixed, radio button, checked, 2 of 2. Targets fixed. The check is updated.
Focus reaches the current pagePage 1, current page, link
Focus reaches the close buttonDismiss the offer, button

These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

Code

Copy the code

The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

The markup

<div class="ap-tsize" data-ap-target-size>
  <div class="ap-tsize__controls">
    <button type="button" class="ap-btn ap-tsize__show" aria-pressed="false" data-ap-hits>
      <svg class="ap-btn__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8" stroke-dasharray="3 3"/><circle cx="12" cy="12" r="2"/></svg>
      Show hit areas
    </button>
    <fieldset class="ap-tsize__mode">
      <legend class="ap-tsize__legend">Targets</legend>
      <div class="ap-tsize__seg">
        <label class="ap-tsize__opt"><input type="radio" name="tsize-mode" value="drawn" checked /><span>As drawn</span></label>
        <label class="ap-tsize__opt"><input type="radio" name="tsize-mode" value="fixed" /><span>Fixed</span></label>
      </div>
    </fieldset>
    <p class="ap-tsize__said" role="status"></p>
  </div>

  <div class="ap-tsize__layout">
    <div class="ap-tsize__card" data-ap-surface>
      <div class="ap-tsize__promo">
        <p class="ap-tsize__promo-text">Free delivery on orders over ₹999.</p>
        <a class="ap-tsize__promo-link" href="#tsize-offers">Shop now</a>
        <button type="button" class="ap-tsize__close" aria-label="Dismiss the offer" data-ap-dismiss>
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 6l12 12M18 6 6 18"/></svg>
        </button>
      </div>

      <div class="ap-tsize__body">
        <h3 class="ap-tsize__name">Write a review</h3>
        <p class="ap-tsize__item">Handloom cotton saree, indigo</p>
        <div class="ap-tsize__editor">
          <div class="ap-tsize__tools" role="toolbar" aria-label="Formatting">
        <button type="button" class="ap-tsize__tool" data-ap-cmd="bold" aria-label="Bold" aria-pressed="false">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M7 5h6a3.5 3.5 0 0 1 0 7H7zm0 7h7a3.5 3.5 0 0 1 0 7H7z"/></svg>
        </button>
        <button type="button" class="ap-tsize__tool" data-ap-cmd="italic" aria-label="Italic" aria-pressed="false" tabindex="-1">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M14 5h-4m4 14h-4m3-14-2 14"/></svg>
        </button>
        <button type="button" class="ap-tsize__tool" data-ap-cmd="underline" aria-label="Underline" aria-pressed="false" tabindex="-1">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M7 4v7a5 5 0 0 0 10 0V4M5 20h14"/></svg>
        </button>
        <button type="button" class="ap-tsize__tool" data-ap-cmd="strike" aria-label="Strikethrough" aria-pressed="false" tabindex="-1">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M16 7a4 3 0 0 0-8 0c0 4 8 2 8 6a4 3 0 0 1-8 1M4 12h16"/></svg>
        </button>
          </div>
          <p class="ap-tsize__review" data-ap-review>Soft handloom cotton, and the indigo is exactly as shown. The pallu could be a little longer.</p>
        </div>
        <p class="ap-tsize__terms">Reviews follow our <a href="#tsize-guidelines">community guidelines</a> and <a href="#tsize-privacy">privacy notice</a>.</p>
        <button type="button" class="ap-btn ap-btn--primary ap-tsize__post" data-ap-post>Post review</button>
      </div>

      <div class="ap-tsize__foot">
        <nav class="ap-tsize__pager" aria-label="Review pages">
          <p class="ap-tsize__foot-k">Reviews</p>
          <ul class="ap-tsize__pages">
            <li><a class="ap-tsize__page" href="#tsize-reviews-prev" aria-label="Previous page" data-ap-step="-1"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m15 6-6 6 6 6"/></svg></a></li>
          <li><a class="ap-tsize__page" href="#tsize-reviews-1" aria-label="Page 1" aria-current="page">1</a></li>
          <li><a class="ap-tsize__page" href="#tsize-reviews-2" aria-label="Page 2">2</a></li>
          <li><a class="ap-tsize__page" href="#tsize-reviews-3" aria-label="Page 3">3</a></li>
            <li><a class="ap-tsize__page" href="#tsize-reviews-next" aria-label="Next page" data-ap-step="1"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m9 6 6 6-6 6"/></svg></a></li>
          </ul>
        </nav>
        <nav class="ap-tsize__help" aria-label="Help topics">
          <p class="ap-tsize__foot-k">Need help?</p>
          <ul class="ap-tsize__links">
            <li><a href="#tsize-delivery">Delivery</a></li>
            <li><a href="#tsize-returns">Returns</a></li>
            <li><a href="#tsize-size-guide">Size guide</a></li>
            <li><a href="#tsize-contact">Contact us</a></li>
          </ul>
        </nav>
      </div>
      <p class="ap-tsize__note" role="status"></p>
      <div class="ap-tsize__overlay" aria-hidden="true" data-ap-overlay></div>
    </div>

    <div class="ap-tsize__report">
      <h3 class="ap-tsize__report-name" id="tsize-report-name">Target check</h3>
      <p class="ap-tsize__sum" data-ap-sum>
        <span class="ap-tsize__stat ap-tsize__stat--pass"><span>Pass</span> <strong data-ap-n="pass" translate="no">0</strong></span>
        <span class="ap-tsize__stat ap-tsize__stat--fail"><span>Fail</span> <strong data-ap-n="fail" translate="no">0</strong></span>
        <span class="ap-tsize__stat ap-tsize__stat--inline"><span>Exempt</span> <strong data-ap-n="inline" translate="no">0</strong></span>
      </p>
      <p class="ap-tsize__key">Counts are for AA: 24 px, or spaced (2.5.8). AAA asks 44 px (2.5.5). On the overlay: a circle badge passes, a square fails, a dotted box is an exempt link in a sentence.</p>
      <div class="ap-tsize__scroll" role="region" aria-labelledby="tsize-report-name" tabindex="0">
        <table class="ap-tsize__table">
          <thead><tr><th scope="col">#</th><th scope="col">Target and size</th><th scope="col"><span class="ap-tsize__th">AA</span> <span class="ap-tsize__th-px" translate="no">24 px</span></th><th scope="col"><span class="ap-tsize__th">AAA</span> <span class="ap-tsize__th-px" translate="no">44 px</span></th></tr></thead>
          <tbody data-ap-rows></tbody>
        </table>
      </div>
    </div>
  </div>
</div>

WCAG 2.2

What it meets

The success criteria this pattern takes care of, and how.

  • 2.5.8 Target Size (Minimum) Level AA

    With Fixed on, every target is at least 24 by 24 px, or so spaced that a 24 px circle on its center touches no other target or circle; links in a sentence are exempt. The check measures each one.

  • 2.5.5 Target Size (Enhanced) Level AAA

    The close button's ::after gives it a 44 by 44 px hit area and Post review is 44 px tall; the check shows which targets reach 44 px and which stop at 24.

  • 2.1.1 Keyboard Level A

    The toolbar, pagination, links and buttons all work from the keyboard; target size helps pointers and touch, and never replaces keyboard access.

  • 2.4.7 Focus Visible Level AA

    Every target, the small ones included, shows a 2 px focus ring that clears 3:1 against the card.

  • 4.1.2 Name, Role, Value Level A

    The format buttons are toggle buttons with aria-pressed inside a named toolbar, and the icon-only buttons and page links have names.

Usage

When to use it

Use it

  • Every interface, and above all dense ones: toolbars, pagination, table row actions, tags, close buttons and footer links.
  • Touch screens, where a fingertip covers 40 px or more and a near miss lands on the neighbor.

Use something else

  • Growing the icon itself when only the hit area is short: padding keeps the design and gives the room.
  • Overlapping hit areas from pseudo-elements on neighbors: the one painted later wins, and the other shrinks.
  • Shrinking targets to fit more on a phone: wrap the row or move actions into a menu instead.

Common failures

How it usually goes wrong

  • Icons packed edge to edge

    Twenty-pixel buttons two pixels apart fail 2.5.8: their 24 px circles overlap. The fixed toolbar keeps the icons and puts them in 28 px buttons.

  • Footer links stacked line on line

    Small links one under another, with no gap, sit closer than 24 px. Padding on each link, not a bigger font, gives every one its own 24 px row.

  • A close button as small as its icon

    A 16 px × passes 2.5.8 only while nothing is near it. An ::after with a negative inset makes it 44 px without moving the layout.

  • Measuring the icon instead of the hit area

    What counts is the area that takes the click: the element's box plus any pseudo-element that is part of it, minus anything on top of it.

  • Treating the inline exception as a loophole

    Links in a sentence are exempt because their size comes from the text. A row of links styled as tags or a footer list is not a sentence.

Notes

Building it

  • Spacing exception, as the check applies it: an undersized target passes if a 24 px circle centered on its box overlaps no other target and no other undersized target's circle.
  • To grow a hit area without moving anything, give the target position: relative and an ::after with position: absolute and a negative inset. Keep neighbors' pseudo-elements from overlapping.
  • The hit areas are measured from getBoundingClientRect plus any absolutely positioned ::before or ::after, read with getComputedStyle(element, "::after").
  • 24 px is the floor, not the aim: the tokens' --ap-target is 44 px, and primary actions here use it.
  • The demo's links point to #… because their pages do not exist here; in a real site they are ordinary links.

Sources: Understanding WCAG 2.2: Target Size (Minimum) · Understanding WCAG 2.2: Target Size (Enhanced) · WAI-ARIA Authoring Practices: Toolbar

Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction