skip to content

In Flutter, how does the Icon widget draw Icons and CupertinoIcons glyphs, and what must pubspec.yaml declare for each set?

level: juniorimportance: must knowfreq 55%

answer

  1. an icon is text, not an image
  2. a code point in a font
  3. one flag under flutter:
  4. a separate package for iOS-style icons
  5. IconTheme fills size and colour

basics

~20 s

Icon draws one character of an icon font. Icons entries are const IconData code points in the MaterialIcons font, bundled only with uses-material-design: true; CupertinoIcons use the CupertinoIcons font from the cupertino_icons package, which must be a dependency.

solid answer

~40 s

`Icon` takes an `IconData` — a code point, a font family and an optional font package — and paints that single character with `RichText` inside a square `SizedBox`, so an icon is really text. `Icons.pets` and its siblings are `static const IconData` values in the `MaterialIcons` font, which the `flutter` tool bundles only when `pubspec.yaml` has `uses-material-design: true` under `flutter:`; the key defaults to false, and the `flutter create` template sets it. `CupertinoIcons.paw` points at the `CupertinoIcons` family inside the `cupertino_icons` package, so that package must be a dependency (the template adds `cupertino_icons: ^1.0.8`). Size and colour come from the `Icon` or the nearest `IconTheme`, with a 24-pixel fallback. Without the right font the code point has no glyph, and the icon renders as a missing-glyph box or blank space.

code

yaml · 7 lines
yaml
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8

flutter:
  uses-material-design: true

go deeper

for a junior

Recall that an icon is a font glyph, that uses-material-design: true bundles Material icons, and that CupertinoIcons need the cupertino_icons dependency.

for a middle

Explain how Icon turns IconData into text, how IconTheme supplies defaults, and how matchTextDirection mirrors directional glyphs.

for a senior

Diagnose missing or wrongly tinted icons quickly and set icon theming at the right level so screens stay consistent.

for a principal

Decide when an icon font stops being enough — multi-colour brand marks, per-platform icon sets — and what the team standardises on instead.

## An icon is a character in a font Flutter's `Icon` widget does not load an image. It takes an **`IconData`** — a Unicode **code point**, a **font family** and optionally the **package** that ships that family — and paints that one character with `RichText`, centred in a square `SizedBox` whose side is the icon size. Everything that makes text work therefore applies to icons: the font must be bundled and registered, and the glyph is tinted by a colour rather than carrying its own pixels. For a pet-clinic app, `Icon(Icons.pets)` is a paw glyph at code point `0xe4a1` in the `MaterialIcons` font. ## Material icons and uses-material-design `Icons` is a class of thousands of `static const IconData` fields, all with `fontFamily: 'MaterialIcons'` and no package. The font file itself is not in your project; it ships with the Flutter SDK and is added to the app bundle only when the app's `pubspec.yaml` says so: ```yaml flutter: uses-material-design: true ``` - The key **defaults to false** when absent; `flutter create` writes it as true. - Setting it inserts a `MaterialIcons` family into the generated `FontManifest.json`. - It must be set in the **app's** pubspec. If a dependency package sets it but the app sets `false`, the tool prints an error explaining that the app must enable it for Material icons. - In Flutter 3.47 the Material library is also published as the standalone `material_ui` package; its `Icons` still refer to the same `MaterialIcons` family, so the same flag applies. Some icons are directional. `Icons.arrow_back` is declared with `matchTextDirection: true`, so `Icon` mirrors it in right-to-left locales. `Icons.adaptive.arrow_back` goes further and picks `arrow_back` or `arrow_back_ios` by platform. ## Cupertino icons `CupertinoIcons` fields use `fontFamily: 'CupertinoIcons'` and `fontPackage: 'cupertino_icons'`. The font lives in the **`cupertino_icons` package**, not the SDK, so the app needs it under `dependencies:`; the app template adds `cupertino_icons: ^1.0.8`. Because the family comes from a package, `Icon` passes the package name to its `TextStyle`, which resolves the namespaced family. Version 1.0.0 of the package redrew the glyphs in the rounder SF Symbols style and remapped old names, so an upgrade from 0.1.x changes how existing icons look. ## Size, colour and variable axes `Icon` reads every unset property from the nearest **`IconTheme`**. Material widgets such as `AppBar` and `IconButton` supply their own `IconTheme`; outside them the app theme applies, and at the very bottom sits `IconThemeData.fallback()`: | Property | Fallback value | |---|---| | `size` | 24.0 | | `color` | opaque black | | `fill` | 0.0 | | `weight` | 400.0 | | `grade` | 0.0 | | `opticalSize` | 48.0 | `fill`, `weight`, `grade` and `opticalSize` become `FontVariation`s on the glyph's text style (`FILL`, `wght`, `GRAD`, `opsz`). They change the drawing only when the icon font defines those axes, as a Material Symbols variable font does. ## The same glyph on every platform Because Flutter paints icons itself, `Icons.pets` looks identical on Android, iOS, web and desktop; nothing is borrowed from the operating system. That is usually what a branded pet-clinic app wants, but platform conventions differ for a few symbols — the back arrow, share, more. Two tools handle that: - `Icons.adaptive` returns the Material or iOS-style variant of a small set of such icons based on the current platform. - Choosing between `Icons` and `CupertinoIcons` yourself, per platform, when a screen is built separately for each. Mixing both sets in one screen is legal but tends to look inconsistent, because the two fonts are drawn with different stroke weights and corner styles. ## What goes wrong in practice 1. **Boxes or blanks instead of icons.** `uses-material-design` is missing or false, so the code point falls through to a font with no glyph for it. 2. **Cupertino icons missing.** `cupertino_icons` was removed from `dependencies:` while the code still uses `CupertinoIcons`. 3. **Icons that ignore a size or colour change.** The value was set on a parent's `DefaultTextStyle`, but `Icon` reads `IconTheme`, not the text style. 4. **A back arrow pointing the wrong way in Arabic or Hebrew.** A custom `IconData` for a directional glyph was created without `matchTextDirection: true`. ## Why icon fonts are the default A font glyph scales without blur at any size, takes its colour from the theme, and costs one font file for the whole set. The trade-off is one colour per glyph: multi-colour brand art needs SVG or vector graphics instead.

  • Icons render as empty boxes in a new Flutter app. What do you check first?
    Whether `pubspec.yaml` has `uses-material-design: true` under the `flutter:` key; without it the `MaterialIcons` font is never bundled and the code points have no glyph. For `CupertinoIcons`, check that `cupertino_icons` is still under `dependencies:`. After fixing either, stop and re-run the app so the build regenerates the font manifest.
  • Why does wrapping an Icon in a DefaultTextStyle with a new colour not recolour it?
    `Icon` builds its own `TextStyle` with `inherit: false` from the `IconData` and the nearest `IconTheme`, so ambient text styles never reach it. Set `color` on the `Icon`, or wrap the subtree in an `IconTheme` (Material widgets like `IconButton` and `AppBar` already provide one).

saying these in an interview costs you the question

  • The Icon widget loads a small PNG image for each Icons constant.
  • Material icons are always bundled, whatever uses-material-design says.
  • CupertinoIcons ship inside the Flutter SDK with no extra dependency.
  • An Icon picks up its colour from the surrounding DefaultTextStyle.
  • Icon's weight and fill change any icon font, variable or not.