vue-material-design-icons
Material Design Icons packaged as individual, tree-shakeable Vue single-file components.
Repository Health
Technical Analysis
vue-material-design-icons packages the entire Templarian MaterialDesign icon set as individual Vue single-file components, one .vue file per icon. Rather than shipping an icon font or a single monolithic sprite, every icon is generated at build time from @mdi/js into its own self-contained SFC, so consumers import only the icons they actually use and register them as local or global Vue components.
Each generated component shares the same small, accessible API: a title prop that supplies both a hover tooltip and a screen-reader label (icons are aria-hidden until a title is given, forcing developers to make a deliberate accessibility choice), a fillColor prop for setting color without extra CSS, and a size prop that controls width and height. An optional shared stylesheet lets icons scale with surrounding text for teams that prefer CSS-driven sizing over the size prop.
What You Get
- The full Material Design Icons set (thousands of icons) as individual Vue single-file components
- Consistent pascal-cased component naming that maps directly to the public MaterialDesign icon names
- Built-in accessibility handling via the title prop (aria-hidden by default, aria-label when a title is set)
- fillColor and size props for styling icons without writing custom CSS
- An optional shared stylesheet for text-relative icon scaling
Common Use Cases
- Adding icon buttons, menus, and nav items to a Vue 2 application
- Building accessible icon-only controls that require a meaningful screen-reader label
- Standardizing on one icon set across a Vue 2 design system instead of ad-hoc SVG imports
- Replacing an icon font with scalable, tree-shakeable SVG components
Under The Hood
Architecture
The project has no runtime logic of its own beyond the generated components; its real architecture is a build-time code generator (build.ts) that iterates every icon exported by @mdi/js’s commonjs build, converts each mdiSomeIconName export into a PascalCased component name and a kebab-cased title, and renders a static Vue SFC template string to dist/. Every generated component is a small, self-contained presentational leaf with three props (title, fillColor, size) and a single click emit — there is no shared state, routing, or data layer, so changing the core abstraction means regenerating the templates rather than touching a deep dependency graph.
Tech Stack
The library targets Vue 2 (vue ^2.7.14, vue-template-compiler), with the generator script itself written in TypeScript and executed directly via a ts-node/register/transpile-only shebang rather than a compiled build step. Icon path data comes from @mdi/js, file writes are batched with p-map to avoid overloading memory across thousands of icons, and Babel (@babel/core, @babel/preset-env) transpiles code for the Jest test environment. CircleCI runs the build and test suite on every push and hands releases to semantic-release for automated npm publishing.
Code Quality
Testing is intentionally narrow: a single __tests__/icon.js suite mounts one representative generated icon (Android) via @vue/test-utils and Jest, covering the title prop, the fillColor prop, click event emission, and a rendering snapshot — reasonable given that every other icon shares the exact same template. CI enforces this suite before release. TypeScript with strict settings governs only the build script itself (noEmit, strict, noUncheckedIndexedAccess); the generated .vue components ship as plain, untyped JavaScript. Prettier enforces formatting, but no ESLint or other static-analysis config is present in the repo.
API Design
Day-to-day usage is a single import per icon (import MenuIcon from 'vue-material-design-icons/Menu.vue') with no registry or wrapper required, which keeps the boilerplate for any one icon minimal. The three props are small and self-explanatory, and the accessibility default (hidden from screen readers unless a title is supplied) nudges consumers toward correct usage rather than silently doing the wrong thing. The tradeoff is that consumers must consult the README to map a public MaterialDesign icon name to its pascal-cased file name, and there are no TypeScript prop types shipped with the components.