[{"data":1,"prerenderedAt":10},["ShallowReactive",2],{"guide-use-material-symbols-in-react-and-vue":3},{"slug":4,"title":5,"description":6,"date":7,"order":8,"html":9},"use-material-symbols-in-react-and-vue","Using Material Symbols in React and Vue","How to use Google's Material Symbols as components in React and Vue — with the icon font or as SVG components — plus fill and weight props, accessibility, and keeping bundles small.","2026-09-24",4,"\u003Cp>There are two good ways to use Material Symbols in a React or Vue app: a small component around the \u003Cstrong>icon font\u003C\u002Fstrong>, or \u003Cstrong>SVG files imported as components\u003C\u002Fstrong>. Both work well; the font is more flexible, and SVGs load nothing extra.\u003C\u002Fp>\n\u003Ch2>Approach 1: a component around the icon font\u003C\u002Fh2>\n\u003Cp>First load the font once, in your \u003Ccode>index.html\u003C\u002Fcode> or root layout (see the \u003Ca href=\"\u002Fguides\u002Fuse-material-symbols-in-html-and-css\u002F\">HTML and CSS guide\u003C\u002Fa> for options), or install it with npm:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">npm install material-symbols\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-js\">\u002F\u002F main.js \u002F main.tsx\nimport &quot;material-symbols\u002Foutlined.css&quot;;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>React\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-jsx\">export function Icon({ name, fill = 0, weight = 400, size = 24, label }) {\n  return (\n    &lt;span\n      className=&quot;material-symbols-outlined&quot;\n      style={{\n        fontSize: size,\n        fontVariationSettings: `&quot;FILL&quot; ${fill}, &quot;wght&quot; ${weight}, &quot;GRAD&quot; 0, &quot;opsz&quot; ${size}`,\n      }}\n      aria-hidden={label ? undefined : true}\n      aria-label={label}\n      role={label ? &quot;img&quot; : undefined}\n    &gt;\n      {name}\n    &lt;\u002Fspan&gt;\n  );\n}\n\n\u002F\u002F Usage\n&lt;Icon name=&quot;favorite&quot; fill={1} \u002F&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Vue\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-vue\">&lt;script setup&gt;\nconst props = defineProps({\n  name: { type: String, required: true },\n  fill: { type: Number, default: 0 },\n  weight: { type: Number, default: 400 },\n  size: { type: Number, default: 24 },\n});\n&lt;\u002Fscript&gt;\n\n&lt;template&gt;\n  &lt;span\n    class=&quot;material-symbols-outlined&quot;\n    aria-hidden=&quot;true&quot;\n    :style=&quot;{\n      fontSize: `${size}px`,\n      fontVariationSettings: `&#39;FILL&#39; ${fill}, &#39;wght&#39; ${weight}, &#39;GRAD&#39; 0, &#39;opsz&#39; ${size}`,\n    }&quot;\n  &gt;{{ name }}&lt;\u002Fspan&gt;\n&lt;\u002Ftemplate&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>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.\u003C\u002Fp>\n\u003Ch2>Approach 2: SVG files as components\u003C\u002Fh2>\n\u003Cp>Install the SVG package for the weight you want:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">npm install @material-symbols\u002Fsvg-400\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>React with Vite\u003C\u002Fh3>\n\u003Cp>Add \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fpd4d10\u002Fvite-plugin-svgr\">vite-plugin-svgr\u003C\u002Fa> to your Vite config, then import SVGs with \u003Ccode>?react\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">import HomeIcon from &quot;@material-symbols\u002Fsvg-400\u002Foutlined\u002Fhome.svg?react&quot;;\nimport FavoriteFilledIcon from &quot;@material-symbols\u002Fsvg-400\u002Frounded\u002Ffavorite-fill.svg?react&quot;;\n\nexport function Toolbar() {\n  return (\n    &lt;button aria-label=&quot;Home&quot;&gt;\n      &lt;HomeIcon width={24} height={24} fill=&quot;currentColor&quot; aria-hidden=&quot;true&quot; \u002F&gt;\n    &lt;\u002Fbutton&gt;\n  );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>With Next.js or Create React App the setup differs (Next.js uses \u003Ccode>@svgr\u002Fwebpack\u003C\u002Fcode>), but the idea is the same: each SVG becomes a component.\u003C\u002Fp>\n\u003Ch3>Vue with Vite\u003C\u002Fh3>\n\u003Cp>Add \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fjpkleemans\u002Fvite-svg-loader\">vite-svg-loader\u003C\u002Fa>, then import with \u003Ccode>?component\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-vue\">&lt;script setup&gt;\nimport HomeIcon from &quot;@material-symbols\u002Fsvg-400\u002Foutlined\u002Fhome.svg?component&quot;;\n&lt;\u002Fscript&gt;\n\n&lt;template&gt;\n  &lt;HomeIcon width=&quot;24&quot; height=&quot;24&quot; fill=&quot;currentColor&quot; aria-hidden=&quot;true&quot; \u002F&gt;\n&lt;\u002Ftemplate&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>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 (\u003Ccode>home-fill.svg\u003C\u002Fcode>, \u003Ccode>@material-symbols\u002Fsvg-600\u002F…\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch2>What about MUI?\u003C\u002Fh2>\n\u003Cp>\u003Ccode>@mui\u002Ficons-material\u003C\u002Fcode> contains Google&#39;s \u003Cem>classic\u003C\u002Fem> Material Icons, not Material Symbols. To use Symbols in an MUI app, use MUI&#39;s \u003Ccode>Icon\u003C\u002Fcode> component with the font:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-jsx\">import Icon from &quot;@mui\u002Fmaterial\u002FIcon&quot;;\n\n&lt;Icon baseClassName=&quot;material-symbols-outlined&quot;&gt;home&lt;\u002FIcon&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>or import SVGs as shown above. See \u003Ca href=\"\u002Fguides\u002Fmaterial-symbols-vs-material-icons\u002F\">Material Symbols vs. Material Icons\u003C\u002Fa> for the differences between the two sets.\u003C\u002Fp>\n\u003Ch2>Tips\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Don&#39;t build icon names dynamically from a huge map of SVG imports.\u003C\u002Fstrong> 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.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Hide decorative icons from screen readers\u003C\u002Fstrong> with \u003Ccode>aria-hidden=&quot;true&quot;\u003C\u002Fcode>, and give icon-only buttons an \u003Ccode>aria-label\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Use \u003Ccode>currentColor\u003C\u002Fcode>\u003C\u002Fstrong> so icons follow the text color and work in dark mode without extra CSS.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Every icon page on this site has ready-made React and Vue snippets for the style, fill and weight you pick.\u003C\u002Fp>\n",1790274093752]