june 3, 20263 min read

Zenicons: 3,201 Icons, One npm Package, and Absolutely No Emotional Support for Bad UI Choices

I built a React icon pack with 3,201 typed, tree-shakeable SVGs so your product team can stop screenshotting icons from random dribbble shots at 2 AM. You're welcome.

Dev StoryReactTypeScriptnpmDesign System

Zenicons: 3,201 Icons, One npm Package, and Absolutely No Emotional Support for Bad UI Choices

"Another icon library? Bold strategy."

At some point every frontend engineer reaches the same spiritual checkpoint: your app needs one icon, then three, then forty, then suddenly you are debugging SVG stroke alignment at midnight while pretending this is normal adult behavior.

So yes, I made another icon package.

Because clearly what the JavaScript ecosystem was missing was one more icon library named @bhaumic/zenicons with 3,201 icons, strict typing, and a searchable catalogue. Totally unnecessary. Completely avoidable. And yet, deeply useful.

Why I built it (besides poor life decisions)

I wanted icons that were:

  • Tree-shakeable by default
  • Type-safe in React + TypeScript
  • currentColor friendly for real theming
  • Consistent to generate from raw SVGs
  • Publish-safe for npm without shipping accidental chaos

In short: not a random folder of SVGs lovingly copy-pasted across repos for eternity.

What Zenicons gives you

Zenicons ships as a React-first npm package with:

  • 3,201 typed icon components
  • ESM + CJS + type declarations
  • sideEffects: false for better bundler tree shaking
  • Shared IconBase behavior
  • A searchable live archive at mic-360.github.io/zenicons

And yes, it supports practical props:

  • size (default 24)
  • color (default currentColor)
  • strokeWidth (default 1.5)
  • title for accessibility labels
  • variant (stroke or fill, per icon override)

Because if a component library cannot pass basic accessibility smell tests, it is just decorative debt with a README.

Install like a responsible engineer

bash
npm install @bhaumic/zenicons
npm install @bhaumic/zenicons

If you like deterministic installs from source snapshots:

bash
npm install github:Mic-360/zenicons#v0.1.0
npm install github:Mic-360/zenicons#v0.1.0

Usage (no blood sacrifices required)

tsx
import { IconAddressBookEmail, IconSigma } from '@bhaumic/zenicons'

export function Example() {
  return (
    <div style={{ color: 'tomato' }}>
      <IconAddressBookEmail />
      <IconAddressBookEmail size={32} color="royalblue" strokeWidth={2} />
      <IconSigma size={48} title="Sigma icon" />
    </div>
  )
}
import { IconAddressBookEmail, IconSigma } from '@bhaumic/zenicons'

export function Example() {
  return (
    <div style={{ color: 'tomato' }}>
      <IconAddressBookEmail />
      <IconAddressBookEmail size={32} color="royalblue" strokeWidth={2} />
      <IconSigma size={48} title="Sigma icon" />
    </div>
  )
}

The icon inherits your text color by default. This is how it should have been from day one, but history had other plans.

The boring engineering bits that actually matter

Most icon packs stop at "it renders." Zenicons also enforces release hygiene:

  • Tarball verification before publish
  • Controlled publish surface
  • npm provenance through GitHub Actions
  • Lockfiles committed for package and demo

In other words: fewer supply-chain surprises, fewer accidental file leaks, fewer Friday-night rollback adventures.

Live search, because scrolling 3,201 names manually is a cry for help

The live site exists for one reason: quickly find an icon and copy the import without memorizing naming gymnastics.

  • Press Ctrl/⌘ + K or /
  • Search by fragment
  • Copy import instantly
  • Move on with your life

Final thoughts

Could I have reused a giant existing icon set and called it a day? Yes.

Would I have learned as much about generation pipelines, packaging discipline, and release safety? Not even close.

Zenicons is for teams that want icons to be infrastructure, not drama.


Thanks for reading. If this saved you one SVG alignment rage-session, my work here is done.