Using Material Symbols in React and Vue
By Colton Griffith · Updated
There are two good ways to use Material Symbols in a React or Vue app: a small component around the icon font, or SVG files imported as components. Both work well; the font is more flexible, and SVGs load nothing extra.
Approach 1: a component around the icon font
First load the font once, in your index.html or root layout (see the HTML and CSS guide for options), or install it with npm:
npm install material-symbols
// main.js / main.tsx
import "material-symbols/outlined.css";
React
export function Icon({ name, fill = 0, weight = 400, size = 24, label }) {
return (
<span
className="material-symbols-outlined"
style={{
fontSize: size,
fontVariationSettings: `"FILL" ${fill}, "wght" ${weight}, "GRAD" 0, "opsz" ${size}`,
}}
aria-hidden={label ? undefined : true}
aria-label={label}
role={label ? "img" : undefined}
>
{name}
</span>
);
}
// Usage
<Icon name="favorite" fill={1} />
Vue
<script setup>
const props = defineProps({
name: { type: String, required: true },
fill: { type: Number, default: 0 },
weight: { type: Number, default: 400 },
size: { type: Number, default: 24 },
});
</script>
<template>
<span
class="material-symbols-outlined"
aria-hidden="true"
:style="{
fontSize: `${size}px`,
fontVariationSettings: `'FILL' ${fill}, 'wght' ${weight}, 'GRAD' 0, 'opsz' ${size}`,
}"
>{{ name }}</span>
</template>
The advantage: any icon is one prop away, and fill and weight change instantly (and can be animated). The cost is the font download, which includes every icon unless you subset it.
Approach 2: SVG files as components
Install the SVG package for the weight you want:
npm install @material-symbols/svg-400
React with Vite
Add vite-plugin-svgr to your Vite config, then import SVGs with ?react:
import HomeIcon from "@material-symbols/svg-400/outlined/home.svg?react";
import FavoriteFilledIcon from "@material-symbols/svg-400/rounded/favorite-fill.svg?react";
export function Toolbar() {
return (
<button aria-label="Home">
<HomeIcon width={24} height={24} fill="currentColor" aria-hidden="true" />
</button>
);
}
With Next.js or Create React App the setup differs (Next.js uses @svgr/webpack), but the idea is the same: each SVG becomes a component.
Vue with Vite
Add vite-svg-loader, then import with ?component:
<script setup>
import HomeIcon from "@material-symbols/svg-400/outlined/home.svg?component";
</script>
<template>
<HomeIcon width="24" height="24" fill="currentColor" aria-hidden="true" />
</template>
Each import only adds that one icon to your bundle, so this is the lightest option when you use a few dozen icons. Different fills and weights are different files (home-fill.svg, @material-symbols/svg-600/…).
What about MUI?
@mui/icons-material contains Google's classic Material Icons, not Material Symbols. To use Symbols in an MUI app, use MUI's Icon component with the font:
import Icon from "@mui/material/Icon";
<Icon baseClassName="material-symbols-outlined">home</Icon>
or import SVGs as shown above. See Material Symbols vs. Material Icons for the differences between the two sets.
Tips
- Don't build icon names dynamically from a huge map of SVG imports. Importing every SVG to look them up by name puts the whole set in your bundle. If you need dynamic names, the font is the better fit.
- Hide decorative icons from screen readers with
aria-hidden="true", and give icon-only buttons anaria-label. - Use
currentColorso icons follow the text color and work in dark mode without extra CSS.
Every icon page on this site has ready-made React and Vue snippets for the style, fill and weight you pick.
Find the icons mentioned here with the icon search, or read another guide.