Lucide Icons
Stroke-based 24×24 icons with a line weight you can actually change
lucide-reactOverview
Lucide is a stroke-based icon set that began as a community fork of Feather Icons and has grown to about 1,500 icons. Every icon is drawn as open lines on a 24×24 canvas with a default 2px stroke and rounded caps and joins, so a toolbar built from Lucide looks like one person drew it. The lines are real SVG strokes, which means one prop makes the whole set thinner or bolder. Fill-based libraries can’t do that.
At a Glance
- Version examined
- lucide-react 0.460.0
- Icons in the package
- 1,539 unique (plus 203 alias modules for renamed icons)
- Icons available in Icony
- 1,539
- Canvas
- 24×24 viewBox
- Drawing model
- Strokes:
fill="none",stroke="currentColor" - Default stroke
- 2, round caps and round joins
- Rendered
HouseSVG - 402 bytes (255 gzipped)
- License
- ISC
Design language: what a Lucide icon is made of
Render <House /> to static markup and you get one <svg> with viewBox="0 0 24 24", fill="none", stroke="currentColor", stroke-width="2", and both stroke-linecap and stroke-linejoin set to round. Inside are just two <path> elements: the door and the outer walls. Outer corners are drawn with 2-unit arcs (a2 2 0 0 1) and the door with 1-unit arcs, which is why Lucide reads as soft without looking bubbly.
Because every shape is a stroke rather than a filled outline, line thickness is a live attribute. Pass strokeWidth={1.5} and every line in the icon thins uniformly. Fill-based sets such as Phosphor, Bootstrap Icons and Radix Icons bake the line thickness into the path geometry, so the same prop does nothing there.
The catch is that Lucide has exactly one style, with no official filled or duotone version. Setting fill="currentColor" fills whatever closed shapes happen to exist. That works for a circle or a heart and looks strange on anything built from open lines, like a house or a gear.
What Lucide does well, and where it falls short
- You can adjust the stroke.
absoluteStrokeWidthdivides the stroke by the scale factor (strokeWidth × 24 / size), so atsize={48}the default stroke of 2 is emitted asstroke-width="1"and still looks 2px on screen. - Each icon is a small module. The ES module for
Houseis 594 bytes before minification (385 gzipped), and the package declaressideEffects: false, so bundlers drop icons you never import. - Coverage for product UI is good: arrows, files, text formatting, charts, devices and general-purpose symbols.
- Brand marks are on their way out.
Github,Figmaand a few other logos still ship, but they are marked@deprecatedand slated for removal in v1.0. Don’t build on them; use a dedicated brand-icon set. - There is only one style. If your design uses filled icons for active states, you need a second library or hand-made SVGs.
- Icons get renamed. Lucide renames icons over time and keeps the old name as an alias. In 0.460.0, 203 of the 1,742 icon files are aliases;
home.js, for example, just re-exportshouse.js. Old tutorials still compile, but the docs only list the new name. - 16px needs a different setting. The default stroke of 2 renders 1.33px wide there, which falls between pixels on a 1× screen and looks soft. Many teams drop to 1.5 for dense layouts, which renders exactly 1px at 16px.
When another library is the better pick
- You need matching outline and solid pairs for navigation states. Phosphor has a fill weight for every icon, and Heroicons ships outline and solid sets with identical names.
- You need wide domain coverage (medical, finance, hardware, lots of brand logos). Tabler has almost four times as many icons with the same visual grammar.
- Most of your icons render at 12–16px in dense tables. A set drawn on a small grid, such as Bootstrap Icons (16×16) or Radix Icons (15×15), will look crisper there.
Lucide vs. Tabler vs. Heroicons Outline
Lucide and Tabler render nearly identical root attributes (24×24, 2px strokes, round caps and joins), so they can share an interface without clashing. The practical differences are catalog size (about 1,500 vs. 5,986), the prop that sets line weight (strokeWidth in Lucide, stroke in Tabler), and naming (House vs. IconHome). Tabler also offers about 1,000 filled variants; Lucide offers none.
Heroicons Outline uses a 1.5 stroke and has 324 icons. Next to Lucide at default settings it looks noticeably lighter, so set Lucide to strokeWidth={1.5} if you have to combine them.
Setup pitfalls
Besides lucide-react, the same icons are published for other stacks, including lucide-vue-next, lucide-svelte, and the framework-free lucide package. The notes below are for React.
- Use named imports. Next.js 16 includes
lucide-reactin its defaultoptimizePackageImportslist, so barrel imports are rewritten to per-icon modules automatically. Elsewhere, tree-shaking works as long as you avoidimport * as Icons. - Icon names coming from a CMS or database defeat static imports. Use
lucide-react/dynamicIconImports, a map from kebab-case names to lazyimport()calls, instead of importing the whole namespace. - Lucide 0.460.0 does not add
aria-hiddento the SVG. Addaria-hidden="true"to decorative icons and put anaria-labelon icon-only buttons. - Name clashes are common (
Link,Image,Map). Import theLucideLinkorLinkIconalias rather than renaming by hand.
// Lazy-load an icon whose name is only known at runtime
import dynamicIconImports from 'lucide-react/dynamicIconImports';
import { lazy, Suspense } from 'react';
type Name = keyof typeof dynamicIconImports;
export function CmsIcon({ name }: { name: Name }) {
const Icon = lazy(dynamicIconImports[name]);
return (
<Suspense fallback={<span style={{ width: 24, height: 24 }} />}>
<Icon aria-hidden="true" />
</Suspense>
);
}License: ISC and the Feather lineage
Lucide uses the ISC license, which works like MIT: you can use, modify and ship the icons in commercial products without paying or asking. The one obligation is to keep the copyright and license notice with copies of the software. In practice that means the LICENSE file in your repository or a third-party notices page.
Lucide grew out of Feather Icons, so the notice also carries Feather’s MIT copyright for the inherited parts. Keep both lines. You don’t have to credit Lucide in your interface.
Key Features
- Real SVG strokes:
strokeWidthchanges line weight on every icon absoluteStrokeWidthkeeps lines the same pixel width at any size- One ES module per icon and
sideEffects: falsefor tree-shaking - Three export names per icon (
House,HouseIcon,LucideHouse) - Packages for React, Vue, Svelte and plain JavaScript
- ISC license: permissive, no attribution needed in your UI
Installation
npm install lucide-reactUsage Example
Basic React usage with Lucide Icons
import { House, Search, Settings } from 'lucide-react';
export function Toolbar() {
return (
<nav className="flex gap-3 text-slate-700">
{/* Decorative: hide from screen readers */}
<House size={20} aria-hidden="true" />
{/* Thinner line for a dense UI */}
<Search size={20} strokeWidth={1.5} aria-hidden="true" />
{/* Icon-only button: the label goes on the button */}
<button aria-label="Settings">
{/* 2px on screen even though the icon is 40px */}
<Settings size={40} absoluteStrokeWidth />
</button>
</nav>
);
}Best For
Common Questions
Can I make Lucide icons filled?
Only partially. Adding fill="currentColor" fills closed shapes, which works for simple icons like Circle or Heart, but icons built from open lines will look broken. If you need designed solid variants, use a library that ships them.
Why do my icons look bolder when I make them bigger?
The stroke is defined in viewBox units, so a stroke of 2 on a 48px icon is 4px on screen. Pass absoluteStrokeWidth to keep the on-screen width constant.
Is Lucide the same as Feather?
It started as a Feather fork and keeps its visual style, but it has many more icons, different names for some of them, and its own release cycle.
Explore Lucide Icons in Icony
Icony has 1,539 icons from Lucide Icons. Browse them, change their color and size, and download PNG or SVG for free.
Open in Icony