An icon library is a choice you make once and then see on every screen for years, which is why the wrong one is so annoying. Icons that fight the design, a bundle that carries a thousand icons to show twelve, or one missing icon that drags in a second library and a second stroke width. In chain testing with several suppliers I can usually tell which screen came from which team by the icons alone, and if I can, users can.
The good news is that the field has settled. Five open-source libraries cover nearly every project, all free for commercial use, all with packages for the main frameworks, and the differences are in the drawing style, the count, the weight per icon and how cleanly they tree-shake. This post compares them so you pick once, and the rule I would put at the top: pick one library, use its stroke width everywhere, and treat the first icon from a second library as a defect.
The five libraries, and what each is for
Lucide (a community fork of Feather, since 2020): - About 1,600 icons, 24 x 24 grid, 2 px rounded stroke - Roughly 400 bytes an icon as a React component - Packages for React, Vue, Svelte, Angular, Solid and Preact, plus plain SVG - ISC licence - Fits: SaaS dashboards, admin panels, developer tools; the default choice when nothing argues for another
Heroicons (Tailwind Labs): - About 300 icons in four styles: outline and solid at 24 px, mini at 20 px, micro at 16 px - Around 500 bytes an icon - Official packages for React and Vue only - MIT - Fits: Tailwind projects, where they were drawn to match; a small set drawn carefully
Phosphor: - About 1,500 icons in six weights: thin, light, regular, bold, fill and duotone - 300 to 600 bytes depending on the weight - React, Vue, Svelte, Flutter, Elm and web components - MIT - Fits: interfaces that need weight for hierarchy, a bold icon on the primary action and a light one everywhere else, without a second library
Tabler Icons: - Close to 6,000 icons, outline and filled, 24 x 24 with an adjustable stroke - About 350 bytes an icon - React, Vue, Svelte, Angular, Solid, Preact, React Native and a web font - MIT - Fits: anything with a long tail of domain-specific icons, where the question is not style but whether the icon exists at all
Bootstrap Icons: - About 2,000 icons, drawn for Bootstrap and usable without it - Around 400 bytes an icon; shipped as SVG files, a sprite and a font - MIT - Fits: Bootstrap projects and server-rendered sites that want a sprite and no build step
Two more worth knowing about: Material Symbols if the product lives in Google's visual language, and Radix Icons if you are already on Radix UI and want the small 15 px set that matches it.

Import by name, and the library's total size stops mattering
Every library here tree-shakes. Import twenty icons by name and the bundle carries twenty icons, so the total count is irrelevant to load time and the per-icon weight is what you pay.
`javascript
// Ships three icons
import { Search, Menu, X } from 'lucide-react';
// Ships all of them
import * as Icons from 'lucide-react';
`
The second form is how a project ends up with 300 KB of icons for a search box, and it usually arrives through a dynamic icon picker that maps a string to a component. If you need that, build the map from the icons you actually use, not from the namespace.
Per icon in a React bundle: Lucide about 400 bytes, Heroicons about 500, Phosphor 300 to 600 by weight, Tabler about 350. Fifty icons is 20 to 30 KB before compression and a fraction of that after, which is smaller than most single images on the page.
For a server-rendered or static site, an SVG sprite is still the cheapest option: one file, one request, wherever the icon appears. Inline the two or three icons in the first screen so they render with the HTML and do not shift the layout when the sprite arrives.
A custom icon drawn to match should go through the SVG Optimizer before it enters the repository, because editors export ids, comments and metadata that the library icons do not carry, and the difference shows up as a 4 KB icon sitting next to 400-byte ones. When an icon has to leave the web, an email signature or a social image, the SVG to PNG converter renders it at the pixel size the target needs.
Every library here tree-shakes.
Which one for which stack
React with Tailwind: Heroicons if the 300 cover you, Lucide if they do not. Same grid, similar stroke, and a Heroicons project that outgrows the set moves to Lucide with little visible change.
Vue: Lucide or Phosphor, both with typed Vue packages. Phosphor's weights are the reason to choose it.
Svelte: Lucide or Tabler, both with dedicated packages. Tabler's size means you will not need a second library for the odd domain icon.
Angular: Lucide or Tabler again; Bootstrap Icons when the project already runs on Bootstrap.
Server-rendered or static HTML: any of them as a sprite. Bootstrap Icons and Tabler ship one ready-made.
React Native: Phosphor and Tabler have native packages; the others go through react-native-svg as components.
Design handover: all five publish Figma libraries. Check that the designer's file and the developer's package are the same library and the same major version, because an icon renamed between versions is a small, irritating defect that recurs on every screen it appears on.
The browser tab icon is a separate job: the Favicon Generator turns the logo or a single library icon into the set of sizes browsers and phones ask for.

Adding a custom icon so nobody can tell
The library will be missing something, usually a product-specific concept, and the choice is a second library or a custom icon. Draw the custom one.
- Same grid, almost always 24 x 24, with the same viewBox
- Same stroke width and the same corner radius on the stroke joins
- Same optical size: icons should look the same size, which is not the same as filling the same pixels; a circle and a square of equal width do not look equal
- Same attribute structure on export,
fill="none",stroke="currentColor", so it takes colour from the text like the rest
If a second library is unavoidable, force its icons to the primary library's stroke width with stroke-width in CSS and make sure the viewBox and display size match. A 20 px icon next to a 24 px one reads as a mistake even to people who cannot say why.
Icon fonts are the older approach and SVG has won: an SVG icon can be labelled for a screen reader, styled per icon, and tree-shaken, and it does not render as a missing-glyph box when the font fails to load. If a project still uses a font, the switch is worth a sprint.
Label what means something, hide what does not:
`jsx
`
An icon-only button without a label is the accessibility defect I log most often in acceptance testing, and the fix is one attribute.
The library will be missing something, usually a product-specific concept, and the choice is a second library or a custom icon.
FAQ
Which library has the most icons?
Tabler, at close to 6,000. Count is the wrong question, though. Search the library for the ten icons your product cannot do without before you look at the total; a 1,600-icon library that has all ten beats a 6,000-icon one that has nine.
Are they free for commercial use?
Yes. Lucide is ISC, the other four are MIT, none needs attribution. Read the licence file once anyway, and again after a major version.
How do I change icon colour and size?
The icons use currentColor, so the CSS color of the parent sets the icon colour. Size is width and height, or the size prop on the framework components, which all five provide.
Self-host or CDN?
Self-host. A CDN is an external dependency and a point of failure for something that weighs 20 to 50 KB in total, and self-hosting gives you the version pinning that stops an icon changing shape under you.
Instagram Image Sizes in 2026: The Pixels, the Safe Zones, and the 3:4 Grid
The exact dimensions Instagram uses in 2026 for feed posts, the 3:4 profile grid, Stories, Reels, carousels and profile photos, with the safe zones that keep text on screen and the export settings that survive its compression.
Glassmorphism in CSS: The Frosted Glass Effect Done Right
The four-line backdrop-filter recipe for frosted glass, the dark mode version, how many glass layers a phone can take, the contrast check most glass UIs fail, and the pages where I would not use it at all.
Favicons for Dark Mode: One SVG That Adapts, and the Files Around It
A dark logo vanishes on a dark tab bar. The fix is an SVG favicon with a media query inside it, plus the ICO, Apple touch icon and manifest PNGs that still have to exist. What works where, and how to test it.
Favicon Generator: All Sizes from One Image
Generate favicons for every browser and device from a single image. Get ICO, PNG, Apple Touch Icon, and web manifest icons in all required sizes.