The standard UI icon sizes are 16, 20, 24 and 32px. Use 16px beside small text in tables and inputs, 20px in dense toolbars, sidebars and menus, 24px for navigation, tab bars and primary buttons, and 32px or more for an icon that stands on its own. Whatever size the icon is, the area a finger taps should be bigger: at least 24 by 24px for WCAG 2.2 AA, 44 by 44pt on iOS and 48 by 48dp on Android.
Those numbers come from two grids lining up, and the same arithmetic explains why some of them look slightly out of focus. Every Pikaicon is drawn on a 24 by 24 grid with a 2px stroke, and here is the calendar at all four sizes, drawn the way a standard-density screen draws it, with every pixel blown up so you can count them.
Which size goes where
An icon has to match the text and controls around it before it has to match its own grid. A 24px icon beside 13px table text looks shouted, and a 16px one looks like it belongs. Here is where each size usually goes.
| Size | Where it goes | Text beside it | A 2px stroke becomes |
|---|---|---|---|
| 16px | Table rows, inputs, badges, inline actions | 12 to 14px, on a 16px line | 1.33px |
| 20px | Toolbars, sidebars, menus, secondary buttons | 14 to 15px, on a 20px line | 1.67px |
| 24px | Navigation, tab bars, primary buttons, list rows | 16px, on a 24px line | 2px |
| 32px | Empty states, settings headers, feature cards | Headings | 2.67px |
| 48px | Onboarding, marketing pages, icons used as illustration | Display type | 4px |
Design systems that publish their sizes land on the same set. IBM's icons are designed for 16, 20, 24 and 32px, with the 16 and 20px sizes tuned to sit beside 14pt and 16pt IBM Plex. Material Design displays system icons at 24dp and lets dense desktop layouts drop them to 20dp, and Heroicons ships 24px outline and solid sets alongside a separate 20px "Mini" set and 16px "Micro" set.
Most products need two of these sizes, not five. A pair like 20 and 24 covers almost every control, and choosing it early stops the slow drift where every new screen invents a size of its own.
A grid on top of a grid
An SVG icon has its own coordinate system, set by its viewBox. A Pikaicon's is 0 0 24 24, so at 24px one unit of the drawing is exactly one pixel of the screen, and a 2px stroke centred on a whole-number line covers two full rows of pixels.
At any other size the drawing is scaled first. At 16px a unit is two thirds of a pixel, so the stroke is 1.33px wide and the calendar's middle bar, which sits on line 10 of the grid, lands at 6.67px. The screen can't light a third of a pixel, so it fills one row and shades the next one grey: anti-aliasing doing its job, and next to crisp text it reads as slightly out of focus.
You don't have to take that on trust. Drawing the stroke calendar onto a canvas in Chrome at each size and reading how much ink lands in each pixel down the middle of that bar gives these numbers.
| Icon size | Stroke on screen | Pixel rows across the bar |
|---|---|---|
| 16px | 1.33px | 100% · 25% |
| 20px | 1.67px | 50% · 100% · 25% |
| 24px | 2px | 100% · 100% |
| 32px | 2.67px | 100% · 100% · 75% |
| 48px | 4px | 100% · 100% · 100% · 100% |
Chrome rounds coverage to quarters, and other renderers give slightly different numbers with the same pattern. The surprise is 20px, which smears the bar across three rows, two of them grey, where 16px gets away with one.
The rule that falls out of this is simple. Sizes that are whole multiples of the drawing grid keep the grid, so a 24px set is pixel-perfect at 24, 48 and 72px, and every other size is a compromise of some degree. Curves and diagonals are anti-aliased at every size anyway; it's the straight edges, the ones your eye compares with text, that show the difference.
Why a thinner stroke won't fix 16px
The instinct with a soft small icon is to change its stroke. Here is the same calendar at 16px with four stroke widths. Measured across the middle bar, 1px gives 75% · 25%, 1.33px (as drawn) gives 100% · 25% and 1.5px gives 100% · 50%.
Thinning the line to 1px makes it fainter and still leaves it soft, because the bar no longer fills a single row. Thickening it to 1.5px gives it back weight but grows the grey edge. The problem at 16px is where the line sits, at 6.67px, and no stroke width can move it onto a whole pixel.
Only a drawing made for the smaller grid fixes the edges. That's why Heroicons draws its Micro set on a 0 0 16 16 viewBox, and why Google's Material Symbols has an optical size axis from 20 to 48dp that adjusts stroke weight as the symbol shrinks. Pikaicons, like Lucide, scales one 24px drawing to every size: every size stays the same shape, and the price is a soft edge at 16 and 20px on a 1x screen.
Weight is still worth tuning, as a matter of taste: a 1.33px line can look faint beside 13px text. In the Pikaicons app you set the size and stroke width before you copy an icon. In your own code, remember that stroke-width is measured in the drawing's units, so stroke-width="2" on a 16px icon draws 1.33 screen pixels.
To set the stroke in screen pixels instead, multiply the width you want by 24 and divide by the icon size (1.5px at 16px is stroke-width="2.25"), or let the browser do the maths with vector-effect: non-scaling-stroke, which MDN lists as widely available since July 2020. Lucide's React package has a nonScalingStroke prop that does the same.
/* A 1.5px line on screen, whatever size the icon is drawn at */
.icon-sm path {
stroke-width: 1.5px;
vector-effect: non-scaling-stroke;
}
Filled icons need none of this, which is one reason they hold up well at small sizes. Their interiors are solid pixels and only the outer edge is shaded, so a solid icon at 16px keeps its weight; outline versus filled icons covers when to use which.
Screen density moves the grid
Everything above assumes one CSS pixel is one device pixel. On a 2x screen a 16px icon is drawn with 32 device pixels, so its bar becomes 100% · 100% · 75% instead of 100% · 25%: darker, with a grey edge half the physical width it was. On a 3x phone the softness all but disappears.
Fractional scaling turns the rule upside down. On a display set to 150%, a devicePixelRatio of 1.5, a 24px icon is 36 device pixels and its bar lands on half pixels, measuring 50% · 100% · 100% · 50%. A 16px icon at 150% is exactly 24 device pixels, the sharpest it will ever be.
So "sharp at 24px" really means sharp at 24 device pixels. That's why an icon set can look fine in Figma on a high-density laptop and soft on a 1x external monitor, and why checking your two chosen sizes at the densities your users actually have catches problems no mock-up shows.
Lining icons up with text
A good rule of thumb is to make the icon as tall as the line height of the text beside it. A 14px label on a 20px line pairs with a 20px icon, and a 16px label on a 24px line pairs with a 24px one. The icon and the first line of text then share a box, and centring them is one line of CSS.
.label {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 14px;
line-height: 20px;
}
.label svg {
width: 20px;
height: 20px;
flex: none; /* stops a long label from squashing the icon */
}
IBM's guidance makes the same call: centre icons next to text rather than aligning them to the baseline.
Two small traps undo the alignment. Sizing an icon in em gives sizes between the grid steps (1.25em of 14px text is 17.5px), and odd padding can put a crisp size on a half pixel (a 24px icon centred in a 41px button starts 8.5px in), so keep UI icons on fixed sizes and even padding, and save em sizing for icons inside running prose.
Tap targets are a different number
The size of an icon and the size of the thing you tap are separate decisions. A 24px icon inside a 24px button gives a finger almost nothing to hit, so the button around the icon needs padding, and the guidelines agree on that direction while differing on the number.
- WCAG 2.2 success criterion 2.5.8 (level AA) asks for targets of at least 24 by 24 CSS pixels. A smaller target passes if a 24px circle centred on it doesn't overlap another target or its circle, so 20px buttons with a 4px gap pass and 20px buttons with no gap fail.
- Success criterion 2.5.5 (level AAA) asks for 44 by 44 CSS pixels.
- Apple's Human Interface Guidelines give 44 by 44pt as the default control size on iOS and iPadOS and 28 by 28pt as the minimum; on macOS the default is 28 by 28pt and the minimum 20 by 20pt.
- Android's accessibility guidance recommends touch targets of at least 48 by 48dp, and allows smaller ones for precise input like a mouse or trackpad.
The 44px figure is often quoted as the WCAG minimum, but at AA the minimum is 24px; 44 is the AAA level and Apple's default. In practice a 24px icon gets 10px of padding on every side to reach 44px, or 12px to reach 48. On desktop, a 20px icon in a 32px button is common and clears the AA minimum with room to spare.
Write the sizes down
Start from the text. Find the two or three line heights your interface uses most, give each its matching icon size, and check the smallest one at 1x; if it looks faint, try a heavier stroke or the solid style there.
Then write the sizes down as design tokens, because the next screen someone builds will reach for whatever size is nearest to hand.
:root {
--icon-sm: 16px; /* tables, inputs, 12 to 14px text */
--icon-md: 20px; /* toolbars, menus, 14px text */
--icon-lg: 24px; /* navigation, tab bars, 16px text */
--tap-target: 44px; /* the hit area around any icon button */
}
A product with two icon sizes used everywhere looks more deliberate than one with five used well. You can try the pairings with the 500+ free icons, which copy as SVG or JSX, or with the full library of 5,000+ icons across five styles on any plan.
App icons and favicons are a different job
If you searched for icon sizes because you're making an app icon or a favicon, the rules flip. Those are single pieces of artwork that the system scales down for you, so you supply one large master, plus a few small sizes for the favicon.
| Where it appears | What you supply | Source |
|---|---|---|
| iOS, iPadOS and macOS app icon | 1024 × 1024px; the system scales it for Settings and notifications | Apple HIG |
| watchOS app icon | 1088 × 1088px | Apple HIG |
| Android adaptive icon | Layers of 108 × 108dp, with the inner 66 × 66dp never masked | Android Developers |
| Google Play listing | 512 × 512px, 32-bit PNG, up to 1024KB | Google Play |
| Web app manifest | At least 192 × 192 and 512 × 512px for Chromium | web.dev |
| iPhone home screen bookmark | An apple-touch-icon; Apple's example gives 180 × 180px for Retina iPhones | Apple |
| Browser tab favicon | Usually 16 × 16px, and an ICO file can hold several sizes | MDN |
The grid logic still applies to the small ones. An ICO file holds several sizes (this site's has 16, 32 and 48px renders of one SVG), and the 16px one deserves a look at 1x, because a favicon drawn on a 24px grid is soft at 16px for exactly the reasons above.
Frequently asked questions
What is the standard icon size for UI design?
24px is the most common default, for navigation, tab bars and buttons, with 16 and 20px for dense interfaces and text-sized icons and 32px or more for icons that stand alone. Material Design, IBM and Heroicons all build on that set.
Should a button use a 20px or a 24px icon?
Match the label's line height. A 14px label on a 20px line takes a 20px icon, and a 16px label on a 24px line takes a 24px icon; in a button with no label, size the icon to the text of the buttons next to it.
Why do my 16px icons look blurry?
Most icon sets are drawn on a 24px grid, and at 16px their straight lines land a third of a pixel off the screen's grid, so the edges are shaded grey. Use the solid style at that size, a set drawn for 16px, or accept it on high-density screens, where the effect nearly vanishes; changing the stroke width won't fix it.
What size should icons be on mobile?
24px suits tab bars and toolbars (Material Design displays system icons at 24dp), inside a tap target of at least 44 by 44pt on iOS or 48 by 48dp on Android. The icon can be smaller than the target, because the padding around it is what a finger hits.
Does WCAG require 44px touch targets?
Only at level AAA. Level AA (success criterion 2.5.8 in WCAG 2.2) requires 24 by 24 CSS pixels, or enough spacing around a smaller target that a 24px circle centred on it doesn't touch its neighbours.
Should I change the viewBox to resize an SVG icon?
No. Keep the viewBox at the grid the icon was drawn on, 0 0 24 24 for Pikaicons, and change only width and height (or the CSS size); the SVG icons in React guide shows how to wire that into a component.