Heroicons ships four icon sets, but outline exists at one size
A set of free MIT-licensed high-quality SVG icons for UI development.
At a glance
- What is it?
- An MIT-licensed SVG set from the Tailwind CSS team, delivered as raw files you copy from the site, plus @heroicons/react and @heroicons/vue wrappers. The build produces outline icons at 24 only, the npm release stopped at v2.2.0, and new icons are refused.
- Who is it for?
- Heroicons fits a Tailwind project that wants 24px outline icons, 20 and 16 solids, and a React or Vue component import, and it costs you the update path, since copying raw SVG leaves nothing to upgrade. Do not reach for it if you need a CDN script tag, an Angular package, a Figma export, or new icons added later.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- tailwindlabs/heroicons23,910 ★ · +95
| Repository | 2026-09-22 | 2026-11-14 |
|---|---|---|
| tailwindlabs/heroicons | 23.8k | 23.9k |
95 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The fastest path copies one SVG block and installs nothing
Basic Usage starts by telling you to copy the source for the icon you need from heroicons.com and inline it into your HTML:
<svg
class="size-6 text-gray-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>The attributes carry the whole styling model. Both icon styles are preconfigured to respond to the color CSS property, set by hand or through a utility class such as text-gray-500 in a framework like Tailwind CSS, and the outline variant works by leaving fill at none while drawing with stroke="currentColor". What you get from this route is a copy with no package, no version, and nothing to upgrade. If the icon is later corrected upstream, the copy in your markup is the copy you keep.
Four import paths and one naming convention to memorize
The two framework packages split the same artwork into four subpaths. In @heroicons/react, the 24x24 outline icons come from `@heroicons/react/24/outline`, the 24x24 solid icons from `@heroicons/react/24/solid`, the 20x20 solids from `@heroicons/react/20/solid`, and the 16x16 solids from `@heroicons/react/16/solid`. @heroicons/vue takes the same four paths in the same order. Component names are upper camel case and always end in the word Icon, which is why the example import is `import { BeakerIcon } from '@heroicons/react/24/solid'`. If you are unsure whether an export exists, the icon name list is browsable on UNPKG for each package. The consequence for a reader is that the path segment is part of the API, and a wrong segment is a failed import rather than a fallback.
The lint script checks names, not formatting
There is a prettier.config.js in the repository root, but the lint script does not run Prettier. What lint actually runs is:
node ./scripts/verify-names.jsSo lint is a name verifier, checking the export names that downstream code imports by string. Formatting of the generated SVG is handled elsewhere, by the build itself. The publish path reinforces this ordering: prepublishOnly is npm run build, meaning nothing reaches npm without a full regeneration of all four sets plus both framework packages. For a reader, the practical consequence is that a build passing lint tells you the exports are named correctly, not that anything was reviewed. The scripts directory is also where the wrapper generators live, build.js run once per framework.
The build produces outline at 24 and nothing else
Read the build script's order and the icon inventory is visible: build-24-outline, then build-20-solid, build-24-solid, build-16-solid, then build-react and build-vue. There is no build-16-outline and no build-20-outline anywhere in it. The optimizer configs match that shape exactly, with svgo.24.outline.mjs, svgo.24.solid.mjs, svgo.20.solid.mjs, and svgo.16.solid.mjs sitting at the root as four separate files, one per output set. Each build runs svgo against ./src for its own size and style, writes into ./optimized, then copies the result up into the root numbered directories. The consequence is direct: a 16px or 20px outline icon cannot be produced by this pipeline, so anyone needing one at a small size has to take the 24 outline and scale it, or choose a different set.
New icons are turned away, so the inventory stops where it stops
The Contributing section sets a hard boundary. It welcomes contributions that fix bugs, giving incorrect TypeScript types and an icon exported with a fill instead of a stroke as the examples. Then it states plainly that contributions for new icons are not being accepted, and neither is support for other frameworks like Svelte or SolidJS, with the suggestion that you release your own icons in your own library and build your own packages for any framework you want covered. The consequence for a reader is twofold. The set you get is fixed, so a missing glyph is your problem to solve. And if you are on Angular, Svelte, or Solid, the upstream route is closed, which leaves you maintaining a fork of the wrapper or picking another library.
The npm package publishes three numbered directories, not the wrappers
package.json at 2.2.0 declares a files array of 16/, 20/, 24/, README.md, and LICENSE, so the root package ships the raw SVG sets and the licence. The framework output lands in separate directories that prebuild clears alongside them, with rimraf aimed at ./{16,20,24}, ./{vue,react}/{16,20,24}, and ./optimized/{16,20,24}. That last path explains the optimized/ directory you see in the tree: it is the intermediate that svgo writes before the result is copied into the published folders, not a shipped artifact. Two consequences follow. The optimized copies are regenerated and deleted on every build, so reading from them outside the build is reading a scratch space. And publishing has its own release-channel script beside the build scripts in package.json.
Pushes continued for months after the last tagged release
The version in package.json is 2.2.0, matching tag v2.2.0 dated 2024-11-18, and the tags before it sit further back at v2.1.5 on 2024-07-10 and v2.1.4 on 2024-06-17. The last recorded push to the default branch is 2026-05-12. So the source tree has moved on for months while the published version has not, which is a gap worth planning around rather than a reason to stop using the icons. The concrete consequence is that `npm install @heroicons/react` resolves to the last publish, not to whatever the repository looks like today, and a bug fix you saw committed may not exist in your node_modules. Pin the version you tested and re-check before assuming a fix landed.
No CDN tag, no Angular package, no Figma export
Three delivery paths are described: inline the copied SVG in HTML, import from @heroicons/react, and import from @heroicons/vue. There is no script tag for a CDN, no Angular package, no React Native target, and no Figma or design tool export anywhere in the repository, and the build targets confirm it by covering react and vue only. If you need an Angular component or a drop-in CDN asset, nothing here produces one, and the contribution policy closes the route of asking for it upstream. The consequence is that integration cost sits with you: you write the wrapper, or you accept a different icon set that already ships the framework you are on.
Editorial conclusion
Heroicons fits a Tailwind project that wants 24px outline icons, 20 and 16 solids, and a React or Vue component import, and it costs you the update path, since copying raw SVG leaves nothing to upgrade. Do not reach for it if you need a CDN script tag, an Angular package, a Figma export, or new icons added later. Before you depend on it, pin the package version, and copy only icons you have verified render at the size you use.
Frequently asked questions
Are Heroicons free to use?
Yes. The library is MIT licensed, and it is described as a set of free MIT-licensed high-quality SVG icons for UI development.
how to install heroicons
For the basic route there is nothing to install: copy the source for the icon you need from heroicons.com and inline it into your HTML. The npm route is npm install @heroicons/react or npm install @heroicons/vue.
how to use heroicons in react
Install @heroicons/react, then import each icon individually as a component, for example `import { BeakerIcon } from '@heroicons/react/24/solid'`. Size and colour are applied with the className prop.
Do heroicons work with Vue?
There is a first-party @heroicons/vue package installed with npm install @heroicons/vue. It uses the same four import paths for outline and solid at 24, 20, and 16, and the same Icon suffix naming.
how to use heroicons in angular
No Angular package is documented or built. The repository has react and vue build targets only, and contributions adding support for other frameworks are not being accepted.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tailwindlabs-heroicons)Star history chart for your README
[](https://hysenlabs.com/projects/tailwindlabs-heroicons)Was this useful?