# Tap targets smaller than 44 by 44 pixels

Source: https://easeweb.dev/learn/target-size-enhanced
Topics: Buttons and links > Buttons and links are at least 44 by 44 pixels (WCAG 2.5.5)
The fix: Make every target at least 44 by 44 CSS pixels. Either draw the buttons at 44 pixels, or keep the 32-pixel look and extend each button's hit area to 44 pixels with a pseudo-element, with enough gap that the areas don't overlap.
Test with: target measurement, touch, mouse, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/target-size-enhanced.html https://www.w3.org/WAI/WCAG22/Techniques/css/C44 https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html https://developer.apple.com/design/human-interface-guidelines/accessibility https://support.google.com/accessibility/android/answer/7101858 https://developer.mozilla.org/en-US/docs/Web/CSS/::before

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A shopping basket shows each item on one line: "Linen napkins, Qty 2", then three icon buttons to decrease the quantity, increase it, and remove the item. The buttons are 32 by 32 pixels, 4 pixels apart: the size the [tap targets too small and too close together](/learn/target-size) guide uses to fix the same row at Level AA. With a steady hand they are easy to press.

Someone with a tremor aims at plus and the tap lands 18 pixels to the right of its centre, 2 pixels past its edge: nothing happens. They aim again, and the next tap lands in the gap. Raising the quantity from 2 to 5 takes three presses and, on a bad day, twice as many taps. Nothing breaks; the cost is in the retries.

## Why it fails

WCAG 2.5.5 Target Size (Enhanced), at Level AAA, asks for every pointer target to be at least 44 by 44 CSS pixels. These buttons are 32. They pass 2.5.8 Target Size (Minimum), which asks for 24, so an AA audit finds nothing. W3C's technique C44 meets 2.5.5 by setting the target's size in CSS, as the fixes below do.

Unlike 2.5.8, 2.5.5 has no spacing exception. At AA, a small target passes when a 24-pixel circle centred on it touches no other target and no other small target's circle; at AAA, empty space around the button doesn't count, and the target itself must be 44 by 44. So widening the gap between these buttons is not a fix here. Where two hit areas overlap, the overlapping part doesn't count towards either target's size.

None of the four exceptions applies. These buttons are not inside a sentence or block of text, the browser didn't set their size, no 44-pixel control on the page does the same thing, and nothing about a basket needs them small. The browser lets a button be any size it is given; 32 pixels was a design choice, and a common one.

## Who is affected

The people 2.5.5 is written for are the people 2.5.8 already helps, with more room: compared with these buttons, a 44-pixel target catches a tap up to 6 pixels further out on every side. The same room helps anyone tapping with a thumb on a moving bus, holding a phone in one hand, or tapping with a knuckle or only part of a finger.

## What automation and AI miss

axe-core's `target-size` rule measures against 24 pixels, the Level AA minimum, so it passes this row. axe has no rule for 2.5.5. The audit measures each control's hit area by testing where clicks along its middle land, from the centre outwards, so a pseudo-element that extends the area counts, and records a lead for each kind of control whose hit area is at least 24 pixels both ways but under 44 in either. Links inside a sentence are skipped. It is a lead because only a person can tell whether a 44-pixel control elsewhere on the page does the same thing. Automated click tests press the exact centre of an element, so they never miss a small one. An AI-generated interface built from a component library inherits its button sizes, and the default and small buttons of shadcn/ui and Bootstrap are all under 44 pixels.

## Before: 32-pixel buttons, 4 pixels apart

```html
<div class="line-actions">
  <button type="button" aria-label="Decrease quantity">−</button>
  <button type="button" aria-label="Increase quantity">+</button>
  <button type="button" aria-label="Remove Linen napkins">×</button>
</div>
```

```css
.line-actions {
  display: flex;
  gap: 4px;
}
.line-actions button {
  flex-shrink: 0;
  min-width: 32px;
  min-height: 32px;
  padding: 0;
}
```

- Each target is 32 by 32 pixels, 12 short of 44 in each direction.
- A tap more than 16 pixels from a button's centre, sideways or up and down, misses it.
- The 4-pixel gap doesn't help: space around a target doesn't count towards 2.5.5.

## After: 44-pixel buttons

```html
<div class="line-actions">
  <button type="button" aria-label="Decrease quantity">−</button>
  <button type="button" aria-label="Increase quantity">+</button>
  <button type="button" aria-label="Remove Linen napkins">×</button>
</div>
```

```css
.line-actions {
  display: flex;
  gap: 8px;
}
.line-actions button {
  flex-shrink: 0;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
}
```

1. Raise each button's `min-width` and `min-height` to 44 pixels. The visible button is the whole hit area, so people can see how much room they have.
2. Keep `flex-shrink: 0`, so a narrow screen can't squeeze the buttons back under 44.
3. Widen the gap to 8 pixels, so the larger buttons don't read as one block.

This fixes the Before and passes 2.5.5, and 2.5.8 with it. The HTML does not change.

## After: a 44-pixel hit area, when the buttons must look 32 pixels

```html
<div class="line-actions">
  <button type="button" aria-label="Decrease quantity">−</button>
  <button type="button" aria-label="Increase quantity">+</button>
  <button type="button" aria-label="Remove Linen napkins">×</button>
</div>
```

```css
.line-actions {
  display: flex;
  gap: 12px;
}
.line-actions button {
  position: relative;
  flex-shrink: 0;
  min-width: 32px;
  min-height: 32px;
  padding: 0;
}
/* Part of the button, so a tap on it presses the button. */
.line-actions button::before {
  content: "";
  position: absolute;
  inset: -6px;
}
```

1. Give each button a `::before` that reaches 6 pixels past every edge, with `position: relative` on the button. The buttons still look 32 pixels wide, but the hit area is 44 by 44. A click on a pseudo-element goes to its button.
2. Widen the gap to 12 pixels. With 6 pixels added on each side, neighbouring areas now meet without overlapping, so each keeps its full 44 pixels.
3. Keep `flex-shrink: 0`, so a narrow screen can't squeeze the buttons down.

This fixes the Before and passes 2.5.5, as long as nothing clips or covers the extended area. The area reaches 6 pixels above and below the button too, so the basket line needs at least 6 pixels of padding above and below the buttons, and no ancestor between the button and that padding can have `overflow: hidden`, which would cut the area off.

## Which option to use

Use 44-pixel buttons. They do the same job as the extended hit area with less CSS and nothing invisible to break, and people can see the room they have to aim at. Keep the extended hit area for a design system whose 32-pixel button you can't change: it passes, but people still aim at a 32-pixel shape, and because the area can't be seen, a later change to the gap or the line's padding can make areas overlap or clip without anyone noticing. Spacing the buttons further apart is not an option at this level.

## Implementation decisions

Measure the hit area in CSS pixels, not the icon inside it: padding and pseudo-elements count, and margins do not. A browser hit-tests a rounded button along its rounded edge, and WCAG doesn't say how a round target is measured at this level, so draw a round button inside a square 44-pixel hit area rather than as a 44-pixel circle.

Two widely used component libraries draw their buttons between the two criteria: shadcn/ui's icon buttons run from 24 to 40 pixels, and Bootstrap's buttons are 38 pixels tall, 31 with `.btn-sm`. Apple's design guidelines give 44 by 44 points as the default control size on iOS and iPadOS, and Android's accessibility guidance asks for 48 by 48 density-independent pixels; in a phone's browser, on a page with a `width=device-width` viewport, a point or a density-independent pixel is about one CSS pixel, so the three figures can be compared directly. Set the 44-pixel minimum on the shared icon button, not on each use, so a dense row can't shrink it again.

The exceptions are narrow. A link inside a sentence is exempt, but a row of links outside one, such as a footer or a pager, is not. An equivalent 44-pixel control only counts when it is on the same page and does the same thing; don't rely on one hidden in a menu. A control the browser draws counts as the browser's only while its size is left alone.

## Verify the fix

1. Measure every target in the row with the browser's inspector, including any pseudo-element, and record its width and height: each must be at least 44 pixels.
2. Check that no target's hit area overlaps another's, in every direction, including the buttons on the lines above and below.
3. On a real phone, tap each control several times with a fingertip, a little off its centre on purpose, and confirm that the control you aimed at fires each time and its neighbour never does.
4. Zoom to 200%, narrow the window to 320 pixels, and check that the targets keep their size and their hit areas still do not overlap or get clipped.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared button styles change.

## Limits

This is a starting pattern, not a guarantee for every application. Level AAA is rarely required in full, but a site can meet single AAA criteria such as this one. The guide covers icon buttons in one row; grids, sliders and drag handles need their own checks. A target big enough to hit can still act on the wrong press: [buttons that act on press and can't be cancelled](/learn/pointer-cancellation) covers taking a slip back. Test with the people and devices your users actually have.

---

Get this guide in your coding agent: MCP https://easeweb.dev/mcp (setup at https://easeweb.dev/services/developers)
