material-symbols-v3

matthewharwood's avatarfrom matthewharwood

Material Symbols v3 variable icon font system. Use when adding icons to buttons, navigation, status indicators, or any UI element. Provides 2,500+ icons with fill, weight, grade, and optical size axes. Integrates with project color tokens.

⭐0stars🔀0forks📁View on GitHub🕐Updated Dec 9, 2025

When & Why to Use This Skill

This Claude skill integrates the Material Symbols v3 variable icon font system into web development workflows, providing access to over 2,500 customizable icons. It leverages variable font technology to allow precise control over icon attributes such as fill, weight, grade, and optical size, ensuring high-quality iconography that aligns perfectly with modern UI design tokens and accessibility standards.

Use Cases

  • Enhancing UI components like buttons, navigation bars, and status indicators with scalable, high-quality Material Design icons.
  • Fine-tuning icon aesthetics using variable font axes (weight, grade, optical size) to match specific typography scales and brand styles.
  • Implementing accessible web interfaces by applying ARIA patterns and screen-reader-friendly configurations for icon-only interactive elements.
  • Optimizing web performance by choosing between Google Fonts CDN integration or self-hosted WOFF2 variable font files for offline support.
namematerial-symbols-v3
descriptionMaterial Symbols v3 variable icon font system. Use when adding icons to buttons, navigation, status indicators, or any UI element. Provides 2,500+ icons with fill, weight, grade, and optical size axes. Integrates with project color tokens.
allowed-toolsRead, Write, Edit, Glob, Grep

Material Symbols v3

Material Design 3 icon system using variable fonts. This project uses Material Symbols Outlined loaded from Google Fonts CDN.

  • ux-iconography: UX patterns for icon usage, accessibility, and animations
  • ux-accessibility: ARIA requirements for icon-only buttons
  • utopia-fluid-scales: Type scale tokens for fluid icon sizing

Project Setup

Location: css/styles/icons.css

@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap');

Self-Hosting (Offline)

For offline/production without CDN:

  1. Download from fonts.google.com/icons
  2. Place in /fonts/material-symbols-outlined.woff2
  3. Replace CDN import:
@font-face {
  font-family: 'Material Symbols Outlined';
  src: url('/fonts/material-symbols-outlined.woff2') format('woff2');
  font-weight: 100 700;
  font-style: normal;
}

Basic Usage

<span class="icon">home</span>
<span class="icon">settings</span>
<span class="icon">favorite</span>

Use the icon name from Material Symbols as text content.


Icon Sizes

Class Size Optical Size Use Case
.icon--sm 20px 20 Dense UI, inline text
.icon--md 24px 24 Default, buttons
.icon--lg 40px 40 Emphasis, headers
.icon--xl 48px 48 Hero sections
<span class="icon icon--sm">info</span>
<span class="icon icon--md">info</span>
<span class="icon icon--lg">info</span>
<span class="icon icon--xl">info</span>

Fluid Sizing with Utopia

For icons that scale with typography:

.icon-fluid {
  font-size: var(--step-1);
  --icon-optical-size: 24;
}

Variable Font Axes

Material Symbols is a variable font with 4 axes:

Axis Range Default Purpose
FILL 0–1 0 Outlined (0) vs filled (1)
wght 100–700 400 Stroke weight
GRAD -25–200 0 Fine thickness adjustment
opsz 20–48 24 Optical size optimization

Fill Styles

<span class="icon icon--outlined">favorite</span>  <!-- Outline (default) -->
<span class="icon icon--filled">favorite</span>    <!-- Filled -->

Weight Variants

<span class="icon icon--thin">home</span>     <!-- 100 -->
<span class="icon icon--light">home</span>    <!-- 300 -->
<span class="icon icon--regular">home</span>  <!-- 400 (default) -->
<span class="icon icon--medium">home</span>   <!-- 500 -->
<span class="icon icon--bold">home</span>     <!-- 700 -->

Grade Variants

<span class="icon icon--grade-low">home</span>    <!-- -25: thinner on dark bg -->
<span class="icon icon--grade-normal">home</span> <!-- 0 (default) -->
<span class="icon icon--grade-high">home</span>   <!-- 200: bolder emphasis -->

Custom Variation

.custom-icon {
  --icon-fill: 1;
  --icon-weight: 600;
  --icon-grade: 0;
  --icon-optical-size: 24;
}

Icon Colors

Semantic Colors

<span class="icon icon--primary">check_circle</span>
<span class="icon icon--secondary">info</span>
<span class="icon icon--disabled">block</span>

Inherit from Parent

.icon {
  color: inherit;  /* Default behavior */
}

.btn-primary .icon {
  color: var(--theme-on-primary);
}

State Colors

.icon-success { color: var(--color-success); }
.icon-error { color: var(--color-error); }
.icon-warning { color: var(--color-warning); }

Interactive Icons

<span class="icon icon--interactive">settings</span>
.icon--interactive {
  cursor: pointer;
  transition: color 0.2s ease, transform 0.2s ease;
}

.icon--interactive:hover {
  color: var(--icon-color-primary);
  transform: scale(1.1);
}

.icon--interactive:active {
  transform: scale(0.95);
}

Button Patterns

Icon + Text Button

<button class="btn">
  <span class="icon" aria-hidden="true">add</span>
  <span>Add Item</span>
</button>
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

Icon-Only Button

<button class="btn-icon" aria-label="Settings">
  <span class="icon" aria-hidden="true">settings</span>
</button>
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--min-touch-target);
  min-height: var(--min-touch-target);
  padding: var(--space-xs);
}

Trailing Icon

<button class="btn">
  <span>Next</span>
  <span class="icon" aria-hidden="true">arrow_forward</span>
</button>

Accessibility

Decorative Icons (with visible label)

<button>
  <span class="icon" aria-hidden="true">save</span>
  Save
</button>

Meaningful Icons (icon-only)

<button aria-label="Close dialog">
  <span class="icon" aria-hidden="true">close</span>
</button>

Screen Reader Text

<button class="btn-icon">
  <span class="icon" aria-hidden="true">delete</span>
  <span class="sr-only">Delete item</span>
</button>

High Contrast Mode

@media (forced-colors: active) {
  .icon {
    forced-color-adjust: auto;
  }
}

Common Icons Reference

Icon Name Usage
home home Home/main
menu menu Hamburger menu
arrow_back arrow_back Back navigation
arrow_forward arrow_forward Forward/next
close close Close/dismiss

Actions

Icon Name Usage
add add Create new
edit edit Edit/modify
delete delete Remove
save save Save
search search Search

Status

Icon Name Usage
check_circle check_circle Success/complete
error error Error state
warning warning Warning
info info Information
help help Help

Media

Icon Name Usage
play_arrow play_arrow Play
pause pause Pause
volume_up volume_up Sound on
volume_off volume_off Sound off

Settings

Icon Name Usage
settings settings Settings
tune tune Adjustments
brightness_6 brightness_6 Theme toggle
lock lock Locked/secure

Browse all icons: fonts.google.com/icons


Animation

With Anime.js

import { animate } from 'animejs';

// Wiggle
animate(iconEl, {
  rotate: [0, -10, 10, -10, 10, 0],
  duration: 300,
  ease: 'easeOutQuad'
});

// Bounce
animate(iconEl, {
  scale: [1, 1.2, 1],
  duration: 200,
  ease: 'easeOutBack'
});

CSS Transitions

.icon {
  transition: transform 0.15s ease;
}

.btn:hover .icon {
  transform: scale(1.1);
}

.btn:active .icon {
  transform: scale(0.95);
}

Web Component Wrapper

class MIcon extends HTMLElement {
  static observedAttributes = ['name', 'size', 'filled'];

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback() {
    this.render();
  }

  render() {
    const name = this.getAttribute('name') || 'help';
    const size = this.getAttribute('size') || 'md';
    const filled = this.hasAttribute('filled');

    this.innerHTML = `<span class="icon icon--${size}${filled ? ' icon--filled' : ''}" aria-hidden="true">${name}</span>`;
  }
}

customElements.define('m-icon', MIcon);

Usage:

<m-icon name="home"></m-icon>
<m-icon name="favorite" filled size="lg"></m-icon>

CSS Custom Properties

:root {
  /* Font */
  --icon-font: 'Material Symbols Outlined';

  /* Sizes */
  --icon-size-sm: 20px;
  --icon-size-md: 24px;
  --icon-size-lg: 40px;
  --icon-size-xl: 48px;

  /* Variable font axes */
  --icon-fill: 0;
  --icon-weight: 400;
  --icon-grade: 0;
  --icon-optical-size: 24;

  /* Colors */
  --icon-color: var(--color-on-surface);
  --icon-color-primary: var(--color-primary);
  --icon-color-secondary: var(--color-on-surface-variant);
  --icon-color-disabled: var(--color-outline);
}

Migration from Emoji

Replace emoji icons with Material Symbols:

Old (Emoji) New (Material Symbol)
<span aria-hidden="true">📖</span> <span class="icon" aria-hidden="true">menu_book</span>
<span aria-hidden="true">⚙️</span> <span class="icon" aria-hidden="true">settings</span>
<span aria-hidden="true">🏠</span> <span class="icon" aria-hidden="true">home</span>
<span aria-hidden="true">⭐</span> <span class="icon" aria-hidden="true">star</span>
<span aria-hidden="true">🔒</span> <span class="icon" aria-hidden="true">lock</span>
<span aria-hidden="true">🔊</span> <span class="icon" aria-hidden="true">volume_up</span>
<span aria-hidden="true">🔇</span> <span class="icon" aria-hidden="true">volume_off</span>
<span aria-hidden="true">✓</span> <span class="icon" aria-hidden="true">check</span>

Files

  • css/styles/icons.css - Icon system styles and CSS custom properties