Skip to content

Iconography

AWC UI is built around Material Symbols, Google’s icon font for Material Design 3. Every icon prop in the library takes a Material Symbols ligature — the icon’s name, written as text.

<md-button variant="filled" icon="add">Add item</md-button>

That is the whole API for the common case. 23 components take an icon as a prop and 21 expose an icon slot for anything the prop can’t express.

The pairing isn’t incidental — the library depends on the font’s variable axes:

  • FILL — components animate this axis between 0 and 1 to show selection. A navigation destination’s icon fills as it becomes active; nothing is swapped, the glyph itself morphs. An SVG set cannot do that.
  • opsz (optical size) — glyph weight is tuned per size, so a 20px icon in a dense table doesn’t read thinner than a 24px one in a nav rail.
  • wght — tracks the surrounding type when you change the type scale.
  • One ligature name covers every variant, so icon="settings" is all the markup ever carries.

MD3 specifies Material Symbols as the icon set. Substituting another set works — the slots take any element — but you lose the fill transition and the optical sizing, and the icons will read at a different weight to the components’ own.

Add the stylesheet once, in your app’s <head>:

<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">

The four axis ranges matter. A default request (?family=Material+Symbols+Outlined) gives you a static instance, and the fill animation silently stops working — components will still render, they just won’t morph.

Self-hosting works the same way; point the @font-face at your own copy and keep the axis ranges.

One ligature name per icon — no imports, no SVG
Add Download
Show code for each technology
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">

<!-- index.html — register the AWC UI elements once -->
<script type="module">
  import '@awc-ui/core/define';
</script>

<div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
  <md-button variant="filled" icon="add">Add</md-button>
  <md-button variant="outlined" icon="download">Download</md-button>
  <md-icon-button icon="favorite" aria-label="Favourite"></md-icon-button>
  <md-icon-button icon="delete" variant="tonal" aria-label="Delete"></md-icon-button>
  <md-chip variant="assist" label="Filter" icon="filter_list"></md-chip>
  <md-fab icon="edit" aria-label="Compose"></md-fab>
</div>

A prop takes one Material Symbols name. When you need something else — a brand mark, an SVG, an avatar, a badge — use the slot instead:

Slots take any element — SVG, avatar, brand mark
Custom SVG
Show code for each technology
<!-- index.html — register the AWC UI elements once -->
<script type="module">
  import '@awc-ui/core/define';
</script>

<div style="display:flex; gap:20px; align-items:center; flex-wrap:wrap;">
  <md-button variant="outlined">
    <svg slot="icon" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M12 2 3 7v10l9 5 9-5V7l-9-5Zm0 2.3 6.5 3.6L12 11.5 5.5 7.9 12 4.3Z"/>
    </svg>
    Custom SVG
  </md-button>
  <md-icon-button aria-label="Account">
    <md-avatar name="Ada Lovelace" initials="AL" size="32px"></md-avatar>
  </md-icon-button>
  <md-chip variant="input" label="Ada">
    <md-avatar slot="icon" name="Ada Lovelace" initials="AL" size="24px"></md-avatar>
  </md-chip>
</div>

Slotted content inherits currentColor, so an SVG using fill="currentColor" picks up the component’s own state colours for free.

Icons size themselves from the component, not from you — a 40px icon button and a 56px FAB draw the same ligature at different optical sizes. Set a size directly only for standalone icons:

20, 24, 32 and 48px — opsz keeps the stroke weight even
rocket_launch rocket_launch rocket_launch rocket_launch
Show code for each technology
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">

<!-- index.html — register the AWC UI elements once -->
<script type="module">
  import '@awc-ui/core/define';
</script>

<div style="display:flex; gap:20px; align-items:flex-end;">
  <span class="material-symbols-outlined" style="font-size:20px;">rocket_launch</span>
  <span class="material-symbols-outlined" style="font-size:24px;">rocket_launch</span>
  <span class="material-symbols-outlined" style="font-size:32px;">rocket_launch</span>
  <span class="material-symbols-outlined" style="font-size:48px;">rocket_launch</span>
</div>

MD3’s sizes are 20px (dense UI), 24px (the default), 40px and 48px. Pair font-size with a matching opsz if you go far outside that range.

FILL is what makes a selected icon read as selected. The components drive it themselves — this is the axis animating under a navigation rail’s active destination:

FILL 0 → 0.5 → 1 — one glyph, not three assets
favorite favorite favorite
Show code for each technology
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">

<!-- index.html — register the AWC UI elements once -->
<script type="module">
  import '@awc-ui/core/define';
</script>

<div style="display:flex; gap:28px; align-items:center;">
  <span class="material-symbols-outlined" style="font-size:32px; font-variation-settings:'FILL' 0;">favorite</span>
  <span class="material-symbols-outlined" style="font-size:32px; font-variation-settings:'FILL' 0.5;">favorite</span>
  <span class="material-symbols-outlined" style="font-size:32px; font-variation-settings:'FILL' 1;">favorite</span>
</div>
  • An icon beside a label is decorative — the label names the control, and the component marks the glyph aria-hidden.
  • An icon-only control needs its own name: aria-label on md-icon-button, md-fab and friends. Without it the ligature text is what a screen reader announces, which is the raw icon name.
  • Don’t rely on the icon alone to carry state — pair a status colour with text, per WCAG 1.4.1.

Browse fonts.google.com/icons and copy the name under the glyph. The name is the ligature: chevron_right, more_vert, keyboard_double_arrow_left. Underscores, no spaces.