Skip to content
inklu
wcagwcag-2-2target-sizeaccessibilitycssengineering

Target Size (Minimum): the 24-pixel rule that fails on real phones

A developer's guide to WCAG 2.2 success criterion 2.5.8, Target Size (Minimum) — what the 24px rule requires, the five exceptions, and how to fix it in CSS and JSX.

By Moe· Co-founder, Design7 min read

Open your own product on a phone and try to tap the close button on a modal with your thumb. Not your index finger held flat against the glass — your thumb, at a slight angle, the way people actually hold a phone one-handed on a train. If you missed and hit the overlay behind it, or tapped the wrong item in a row of icons, you just reproduced the exact failure that WCAG 2.2 added a criterion to catch.

That criterion is 2.5.8, Target Size (Minimum), and it is Level AA, which means it is in scope for AODA, ADA Title II, and the EAA — every compliance regime that cites WCAG 2.2 AA. It is also one of the criteria teams miss most, because a target that is comfortable with a mouse cursor can be genuinely unusable with a fingertip, and desktop testing never surfaces it.

What 2.5.8 actually requires

The rule: the target for any pointer input must be at least 24 by 24 CSS pixels, unless it meets one of five exceptions. That is it. Twenty-four CSS pixels square, measured on the clickable target itself — not the icon glyph inside it, the target.

A CSS pixel is not a device pixel. On a phone with a 3x display, 24 CSS pixels is 72 physical pixels, so this is not asking for something microscopic. It is asking for roughly the width of an adult fingertip, which is the whole point. Apple's own human interface guidance has recommended 44 points for years and Google's Material guidance recommends 48dp; WCAG 2.2 set the floor lower, at 24, precisely so that dense interfaces could still pass without a full redesign — as long as they use one of the escape hatches deliberately.

The most common way to fail it is an icon-only button. You drop a 16-pixel SVG into a button, add four pixels of padding on each side, and ship a 24-pixel hit area — right at the line. Then a designer nudges the padding to 3 pixels for visual balance and you are at 22, failing, with no visible change on screen and nothing in a desktop QA pass to catch it.

// Fails 2.5.8: 16px icon + 3px padding = 22px target
<button className="p-[3px]" aria-label="Close">
  <XIcon width={16} height={16} />
</button>

// Passes: force the target to a minimum regardless of icon size
<button
  aria-label="Close"
  className="inline-flex items-center justify-center"
  style={{ minWidth: 24, minHeight: 24 }}
>
  <XIcon width={16} height={16} />
</button>

The fix is almost never to make the icon bigger. It is to guarantee the target is at least 24 square while letting the glyph stay whatever size the design calls for. min-width and min-height on the interactive element, with the icon centered inside, gets you there without touching the visual weight of the icon.

The five exceptions, and which ones are traps

The exceptions are where teams get into trouble, because it is tempting to reach for one to avoid the work rather than because it genuinely applies. Here they are, in plain terms.

Spacing. A target smaller than 24 pixels passes if a 24-pixel-diameter circle centered on it does not overlap the circle of any adjacent target. This is the exception that makes dense toolbars workable: your buttons can be 20 pixels if they are spaced far enough apart that the fingertip-sized circles around them do not collide. The trap is that spacing is measured center to center, and a tightly packed row of icons almost always fails it even when each icon looks like it has breathing room.

Equivalent control. If the same action is available through another control on the same page that does meet the size requirement, the small one is exempt. A tiny inline "edit" pencil is fine if there is also a full-size Edit button in the item's detail view. The trap: the equivalent has to be on the same page and reachable, not buried two navigations away.

Inline. A target inside a sentence or otherwise constrained by the line-height of running text is exempt. A link in the middle of a paragraph does not have to be 24 pixels tall. This one is genuinely safe to rely on — do not add vertical padding to inline links trying to satisfy a rule that does not apply to them.

User agent control. If the browser sizes the control and you have not overridden it — a default checkbox, a native select — it is exempt. The moment you restyle it with custom CSS, you own the size again.

Essential. If a particular presentation is legally required or genuinely essential, it is exempt. Pins on a map are the canonical example: you cannot space them out without changing the information they convey. This is the narrowest exception and the one auditors scrutinize hardest. "It looked better small" is not essential.

If you find yourself arguing that a control is exempt, the honest move is usually to just make it 24 pixels. The exceptions exist for cases where meeting the size would break the interface, not for cases where meeting it is mildly inconvenient.

Where this hides in a real codebase

Target Size failures cluster in predictable places, and knowing the pattern is faster than hunting element by element.

Icon-only buttons are the biggest source: close buttons, kebab menus, sort arrows, quantity steppers, social share rows, carousel dots. Carousel and pagination dots are especially bad because the visible dot is often 8 pixels and the target matches it exactly. Table row actions are the second cluster — a row of small icons at the end of each row, each one under 24 pixels and packed close enough to fail the spacing exception too. Custom checkboxes and radios are the third, because the moment you hide the native input and style a ::before you have taken responsibility for the hit area, and a 16-pixel styled box is a failure the native control would have passed.

/* Common failure: the visible dot IS the target */
.carousel-dot { width: 8px; height: 8px; }

/* Fix: keep the dot small, grow the target around it */
.carousel-dot {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: transparent;
  border: 0;
}
.carousel-dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}

The pattern is the same every time: separate the target from the ornament. The thing the finger lands on is 24 pixels; the thing the eye sees can be whatever the design wants.

Target Size (Enhanced) is a different criterion

Do not confuse 2.5.8 with 2.5.5, Target Size (Enhanced), which is Level AAA and asks for 44 by 44 pixels. Most teams conform to AA, so 24 is your working number. But if you are bidding on a contract that specifies AAA, or you simply want targets that feel good rather than merely legal, 44 is the number that matches the platform guidance from Apple and Google, and hitting it removes a whole class of "I keep missing this button" complaints. There is no penalty for exceeding the AA floor, and on touch-first interfaces there is a real usability argument for doing so.

Catching it before it ships

Target Size is a good example of why source-level scanning matters. An automated engine can measure the computed box of every interactive element and flag the ones under 24 pixels, but the exceptions are contextual — spacing depends on neighbors, equivalent-control depends on the rest of the page — so the honest answer is that this criterion needs both machine measurement and human judgment. Tooling should find the candidates and tell you which exception, if any, might apply, and a person should confirm.

That is the model inklu is built on. We scan against WCAG 2.2 using axe-core v4.11 plus our own rules, flag Target Size violations in your HTML, CSS, JSX, and SCSS, and open a GitHub pull request with the fix — usually a min-width/min-height adjustment or a target-wrapper refactor like the carousel example above. You review the diff, and nothing lands on your default branch without your consent. Because the whole loop happens against your source, the fix is a real code change you own, not a runtime patch layered over the problem. If you want the mechanics of how we score scans and fixes, the token math is on the pricing page and the common questions are in the FAQ.

Target Size is not a hard criterion to satisfy. It is a hard one to remember, because it never shows up when you test with a mouse and it hides inside components you thought were finished. Put a 24-pixel floor on every interactive element in your design system once, and most of the problem disappears at the source.

Book a demo at inklu.io to see it scan your own components, or email hello@inklu.io if you want to talk through where your icon buttons stand.