Flutter Icons and IconButton: Material Icons, Sizes, and Taps

Coding Liquids blog cover featuring Sagnik Bhattacharya for the Flutter Icons and IconButton guide, with Material icon variants, icon sizing, and IconButton tap-target visuals.
Coding Liquids blog cover featuring Sagnik Bhattacharya for the Flutter Icons and IconButton guide.

Icons are everywhere in a mobile UI — in the app bar, on buttons, beside list items — and Flutter splits the job in two: Icon draws a glyph, and IconButton makes that glyph tappable, accessible, and properly sized for a finger. Mixing the two up is the single most common icon mistake. This guide covers the Icon widget and Material icon set, sizing and colour, IconButton with its tap target and tooltip, the Material 3 styled variants, and accessibility, with paste-ready code.

The Complete Flutter Guide course thumbnail

The Complete Flutter Guide: Build Android, iOS and Web apps

Go from scratch to building industry-standard apps with Riverpod, Firebase, animations, REST APIs, and more.

Enrol now

Every snippet below is paste-ready against current stable Flutter. Icons sit beside almost every other widget, so the Material Widgets catalogue and the RichText guide (for inline icons in text) both pair naturally with this one.

Follow me on Instagram@sagnikteaches

We'll work through the Icon widget and the Material icon variants, how size and colour are resolved, the IconButton and its all-important tap target, the Material 3 filled and outlined variants, and how to keep icons accessible.

Connect on LinkedInSagnik Bhattacharya

If watching helps more than reading, the channel wires icons into real toolbars and list items rather than isolated demos.

Subscribe on YouTube@codingliquids

The Icon widget and Material icons

The Icon widget renders a single glyph from an IconData value. Flutter bundles the full Material icon set in the Icons class, so you rarely add an icon font yourself.

Icon(Icons.favorite, size: 28, color: Colors.red)

Most Material icons ship in style variants — the same shape filled, outlined, rounded, or sharp — accessed by a name suffix: Icons.home, Icons.home_outlined, Icons.home_rounded, Icons.home_sharp. Pick one style and use it consistently; mixing outlined and filled icons in the same bar looks unintentional. For iOS-flavoured apps, CupertinoIcons offers the matching SF-style set, covered in the Cupertino widgets guide.

Size and colour resolution

If you omit size and color, the icon doesn't render as a default grey 24px square at random — it inherits from the ambient IconTheme, which Material widgets like AppBar and ListTile set up for you. That's why an app-bar action icon is automatically the right colour without you specifying it.

// Inherits colour/size from the surrounding IconTheme:
const Icon(Icons.settings)

// Override just for this icon:
const Icon(Icons.settings, size: 20, color: Colors.white70)

Setting an IconTheme over a subtree is the clean way to restyle a group of icons at once, rather than passing size and color to each. Reach for explicit arguments only when one icon needs to differ from its neighbours.

IconButton: making an icon tappable

An Icon ignores taps. To respond to a press, use IconButton, which adds a ripple, a tooltip, and — crucially — a 48-by-48 logical-pixel minimum tap target even when the glyph is small, so it's comfortable to hit with a thumb.

IconButton(
  icon: const Icon(Icons.share),
  tooltip: 'Share',          // shows on long-press and to screen readers
  onPressed: () => _share(),
)

The tooltip is not optional polish: it labels the button for accessibility and surfaces a hint on long-press. Set onPressed to null to disable the button — Flutter greys it out and drops the ripple automatically, the same convention every Material button follows.

The Complete Flutter Guide course thumbnail

Build toolbars that feel native

The Complete Flutter Guide covers icons, buttons, and tap targets to Material spec from first principles through to shipped apps.

Enrol now

Material 3 IconButton variants

Material 3 adds named constructors that wrap the icon in a styled container, so you no longer hand-roll a coloured circle behind an icon.

IconButton.filled(onPressed: () {}, icon: const Icon(Icons.add))      // solid background
IconButton.filledTonal(onPressed: () {}, icon: const Icon(Icons.edit)) // soft tonal fill
IconButton.outlined(onPressed: () {}, icon: const Icon(Icons.check))   // bordered outline

The plain IconButton(...) constructor remains the standard, container-less button. The variants share the same onPressed and icon arguments, so switching styles is a one-word change. Use a filled variant for the primary action in a row of icons and the standard one for secondary actions.

Sizing the tap target

Sometimes the default 48px target is too generous — a dense row of small icon buttons, for instance. You can tighten it with constraints and padding, but do so deliberately, because shrinking the target below the recommended minimum hurts usability.

IconButton(
  icon: const Icon(Icons.close, size: 18),
  padding: EdgeInsets.zero,
  constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
  onPressed: () {},
)

This is the right pattern for a tight chip or a compact toolbar, where 48px would force unwanted spacing. Outside those cases, leave the default alone — the spacing exists for a reason.

Accessibility

A bare decorative Icon conveys nothing to a screen reader. Give a meaningful standalone icon a semanticLabel so it's announced, and rely on the tooltip for icon buttons, which doubles as the accessibility label. An icon that merely decorates adjacent text needs no label — the text already carries the meaning.

const Icon(Icons.warning_amber, semanticLabel: 'Warning')

Common mistakes

  • Wrapping an Icon in a GestureDetector for taps. Use IconButton — you get the ripple, the 48px target, and accessibility for free.
  • Forgetting the tooltip. It labels the button for screen readers and shows a hint on long-press.
  • Mixing icon styles. Stick to one of outlined, filled, rounded, or sharp across a screen.
  • Hard-coding colour on every icon. Set an IconTheme over the subtree instead.
  • Shrinking the tap target everywhere. Tighten constraints only in genuinely dense UI, not by default.

Frequently asked questions

What is the difference between Icon and IconButton in Flutter?

Icon is a non-interactive glyph; IconButton is a tappable, accessible button with a ripple, a 48px tap target, onPressed, and a tooltip. Use IconButton whenever the icon should react to a tap.

How do I change icon size and colour in Flutter?

Set size and color on the Icon, or restyle a group by wrapping it in an IconTheme. On an IconButton, use iconSize and color.

What are IconButton.filled and IconButton.outlined?

Material 3 variants that give the button a container — solid, tonal, or outlined. The default IconButton has no container.

How do I disable an IconButton in Flutter?

Set onPressed to null; Flutter greys it out and removes the ripple automatically.

Further reads

Keep going with the tutorials that pair with this guide:

Sources: Flutter documentation — Icon, Icons, IconData, IconButton, IconTheme, and CupertinoIcons API references, plus the Material 3 icon-button guidance (docs.flutter.dev). Verified against current stable Flutter.