Skip to content
Icons

Lucide React — Component Library Guide

Beautiful & consistent icon toolkit made by the community. 1500+ pixel-perfect SVG icons as React components, fully tree-shakeable.

TypeScript ISC
6.3M weekly downloads
12.8k GitHub stars
~1kB per icon bundle size
v0.475.0 latest version
iconssvgtree-shakeableconsistentopen-source

TL;DR: Lucide React is 1500+ pixel-perfect SVG icons as tree-shakeable React components. Import only what you use - each icon adds ~1kB. It's the default icon set in shadcn/ui. Consistent stroke style across the whole set. Official docs: lucide.dev.

What is Lucide React?

Lucide is a community fork of Feather Icons with roughly triple the icon count, active maintenance, and consistent design rules. Each icon is a React component that renders an inline SVG - there's no icon font, no sprite sheet, and no separate asset pipeline.

Icons are tree-shakeable: if you import only CircleCheck and AlertTriangle, only those two SVGs end up in your bundle. That matters more than it sounds. Icon fonts force you to download the entire glyph set even if you use a dozen icons, and they bring their own rendering quirks like blurry edges and baseline alignment headaches. Inline SVG sidesteps all of that. Each icon scales crisply, inherits text color through currentColor, and styles with plain CSS.

Because every icon is drawn on the same 24-pixel grid with the same 2-pixel stroke, the whole set looks like it came from one hand. That visual consistency is the quiet reason designers like it. Mixing icons from three different packs always shows, and Lucide saves you from that by giving you one coherent family that covers nearly everything a typical app needs.

Choosing Lucide for your project

Use Lucide when you want a consistent, large icon set with zero configuration. It's the default icon library in shadcn/ui and is widely used across the React ecosystem, so if you're already in that world the icons will feel at home. The API is about as small as it gets: import a component, set a size, set a color, done.

How does it stack up against Heroicons and Phosphor? All three are solid. Lucide has the broadest selection and the most active community. Heroicons is more opinionated and leans on the Tailwind team's aesthetic, with outline and solid variants only. Phosphor goes the other direction with six weight variants per icon, from thin to bold to duotone, which is great when you want stylistic range but adds decisions you may not want to make. If you just need a big, tasteful, no-fuss set, Lucide is the path of least resistance.

One practical note: icon names occasionally change between major versions as the project tidies its naming. Pin your version and read the changelog before bumping, so a renamed icon doesn't quietly disappear from your build.

Key Features

  • 1500+ icons - covers UI, navigation, media, devices, file types, and more
  • SVG props passthrough - size, color, strokeWidth, and all standard SVG attributes
  • Dynamic imports - use LucideProps type + React.lazy for lazy-loaded icon pickers
  • lucide-react/dynamic - import icons by name string at runtime

Installation

npm install lucide-react

Basic Usage

import { Search, CircleCheck, AlertTriangle, Loader2 } from 'lucide-react'

function StatusIcon({ status }: { status: 'success' | 'warning' | 'loading' }) {
  if (status === 'success') return <CircleCheck className="text-green-500" size={20} />
  if (status === 'warning') return <AlertTriangle className="text-yellow-500" size={20} />
  return <Loader2 className="animate-spin text-gray-400" size={20} />
}

Using Icons as Button Labels

Always pair icon-only buttons with accessible labels:

import { Trash2 } from 'lucide-react'

function DeleteButton({ onDelete }: { onDelete: () => void }) {
  return (
    <button
      onClick={onDelete}
      aria-label="Delete item"
      className="p-2 rounded hover:bg-red-50 text-red-500"
    >
      <Trash2 size={16} aria-hidden="true" />
    </button>
  )
}

Dynamic Icon Lookup

import { icons, type LucideIcon } from 'lucide-react'

function Icon({ name, ...props }: { name: string } & React.SVGProps<SVGSVGElement>) {
  const LucideIcon = icons[name as keyof typeof icons] as LucideIcon | undefined
  if (!LucideIcon) return null
  return <LucideIcon {...props} />
}

// Usage:
<Icon name="Rocket" size={24} />

TypeScript Tips

Use the LucideIcon type when accepting icons as props:

import { type LucideIcon } from 'lucide-react'

interface NavItem {
  label: string
  href: string
  icon: LucideIcon
}

function NavLink({ item }: { item: NavItem }) {
  return (
    <a href={item.href} className="flex items-center gap-2">
      <item.icon size={18} aria-hidden="true" />
      {item.label}
    </a>
  )
}

Bundle size and dynamic loading

For most apps, importing named icons is exactly right and the tree-shaking handles the rest. The trouble starts when you build something like an icon picker that needs access to all 1500-plus icons at once. Importing the entire set defeats tree-shaking and balloons your bundle. For that case, use the lucide-react/dynamic entry point, which lets you load an icon by its name string at runtime and code-splits the rest away. Your picker stays light because it only pulls in the icon a user actually selects.

There's a build-time wrinkle worth knowing. In some bundler setups, importing many icons from the barrel file can slow down dev startup, because the tool processes the whole module map. If you notice sluggish cold starts, importing from the specific icon path can help. Most modern setups handle the barrel import fine, so measure before you optimize.

Common Gotchas

  • size vs width/height - use the size prop (Lucide shorthand) rather than width and height separately, so the icon stays square.
  • strokeWidth - default is 2. Reducing to 1.5 gives a lighter feel; increasing to 2.5 reads better at small sizes.
  • Accessibility - add aria-hidden="true" to decorative icons and aria-label to the parent button; don't put role="img" on decorative SVGs.
  • color and currentColor - by default icons use currentColor, so set color on the parent with text utilities rather than passing a hardcoded color prop you'll forget to theme later.
  • shadcn/ui - Lucide React is the default icon set for shadcn/ui components
  • Radix UI - Radix uses Lucide icons in its documentation examples

Frequently Asked Questions

Does importing Lucide React add all 1500 icons to my bundle?

No. Lucide React is fully tree-shakeable. Each icon is a separate named export. Only the icons you actually import are included in your production bundle. Importing CircleCheck adds only the CircleCheck SVG.

How do I change icon size and stroke width?

Use the size prop for uniform width and height, and the strokeWidth prop for line thickness. The default size is 24px and default strokeWidth is 2. Smaller icons often benefit from strokeWidth 1.5 for a lighter feel.

Can I make icons accessible for screen readers?

For decorative icons, add aria-hidden='true' to the icon element and ensure the surrounding interactive element has a text label or aria-label. For standalone informative icons, add a title and role='img' to the SVG.

How do I use a Lucide icon as a prop type?

Import the LucideIcon type from lucide-react and use it as the TypeScript type for icon props. This allows any Lucide icon component to be passed as a prop without using React.ComponentType.

Is Lucide React compatible with React Native?

No. Lucide React renders SVG elements which are not supported in React Native. Use lucide-react-native, a separate package that renders the same icons using React Native SVG primitives.