Icons
Material Symbols Variable Font integration with customizable axes and hardware-accelerated animations.
The <Icon /> component provides a highly performant wrapper around Google's Material Symbols variable font. Instead of shipping static SVG files, it leverages a single variable font file capable of infinite interpolation across 4 distinct typography axes.
Introduction
Material Symbols are the next generation of Material Icons, designed to be more flexible and expressive. By using a variable font, the <Icon /> component can morph between different weights, fills, and styles without loading multiple assets. This ensures faster load times and smoother animations, especially for state transitions like "liking" or "favoriting" an item.
Anatomy
- Glyph: The visual representation of the icon, defined by its name (ligature).
- Axes: Four parameters (Fill, Weight, Grade, Optical Size) that control the font's geometry.
- Bounding Box: The 24x24dp (default) area that contains the icon, ensuring consistent alignment with other UI elements.
Variants
Stylistic Variants
Material Symbols offers three distinct stylistic variations, each providing a different aesthetic for your application:
- Outlined (Default): Modern, clean lines.
- Rounded: Softer, friendlier geometric forms.
- Sharp: Direct, high-precision geometry.
Features
Variable Font Axes
The <Icon /> component exposes four axes for fine-tuned control:
- Fill: Toggle between outlined (
0) and solid (1) styles. - Weight: Adjust the thickness of the icon strokes (100–700).
- Grade: Fine-tune the stroke weight without affecting the icon's dimensions (-50 to 200).
- Optical Size: Optimize the icon's rendering for specific display sizes (20, 24, 40, 48).
Expressive Animations
By setting animateFill={true}, the icon can smoothly transition between its outlined and filled states. This is powered by motion/react and provides a premium feel to interactive icons.
Usage
Basic Usage
import { Icon } from "@bug-on/m3-expressive";
<Icon name="favorite" />
Advanced Customization
<Icon
name="settings"
weight={600}
fill={1}
grade={100}
opticalSize={48}
/>
Animated Toggle
const [isFavorite, setIsFavorite] = useState(false);
<Icon
name="favorite"
fill={isFavorite ? 1 : 0}
animateFill
onClick={() => setIsFavorite(!isFavorite)}
/>
Best Practices
Do
- Use consistent icon styles (e.g., all Rounded) throughout your application.
- Use Optical Size that matches the icon's actual display size for the clearest rendering.
- Animate the Fill axis for toggle actions like "Like" or "Bookmark" for better feedback.
- Pair icons with text labels or tooltips to ensure their meaning is clear.
Don't
- Don't use different stylistic variants (e.g., Outlined and Sharp) on the same screen.
- Avoid using very light weights (100) on low-contrast backgrounds as they may be hard to see.
- Don't use complex icons at small sizes where they may lose detail.
Accessibility
- Decorative Icons: By default, icons are marked with
aria-hidden="true"as they are usually decorative. - Semantic Icons: If an icon conveys meaning on its own, wrap it in an
IconButtonor provide anaria-labelon a parent element. - Contrast: Ensure the icon color meets WCAG contrast requirements against its background.
API Reference
Icon
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Required. Ligature name (e.g., "search"). |
variant | "outlined" | "rounded" | "sharp" | "outlined" | Stylistic variation. |
fill | number | 0 | Fill level (0 to 1). |
weight | number | 400 | Stroke thickness (100-700). |
grade | number | 0 | Emphasis modifier (-50 to 200). |
opticalSize | number | 24 | Rendering optimization size. |
size | number | 24 | Visual font-size in pixels. |
animateFill | boolean | false | Enables spring animation for fill changes. |
className | string | — | Custom classes. |