# shadcn/ui Icons: How to Use, Swap, and Customize Them

> Everything about icons in shadcn/ui: where Lucide fits in, how to swap in another icon library, sizing and color tweaks, and keeping Figma in sync with code.

Published: 2025-11-13 · Author: Matt Wierzbicki · Canonical: https://www.shadcndesign.com/blog/icons-guide-shadcn-ui

Ever shipped a page and realize every icon looks a little different? One is heavier, one sits a pixel off, and another won't match dark mode. This guide keeps it simple. We'll look at the default Lucide icons you get in the shadcndesign.com Figma kit, how those map to shadcn/ui, and how to add other icon sets using their official npm packages. We'll also cover the basics: installing via npm (not third-party registries), changing size, stroke, and color, and dropping icons into buttons and input groups without breaking layout or accessibility.

## The quick picture

**Default choice:** shadcn/ui ships with Lucide. The shadcndesign.com Figma kit uses Lucide too, so design and code match.

**Other options:** If you want a different style (solid variants, different weights, specialty sets), choose a reputable library and install it from its official npm package (for example, `lucide-react`, `@heroicons/react`, `@radix-ui/react-icons`, `@tabler/icons-react`, `phosphor-react`). Import only the icons you use so bundles stay small.

**Customization:** Adjust size, stroke width, and color through simple props and your Tailwind tokens.

**Placement:** Use icons before or after text in a button, or as prefix/suffix inside an input group. Keep spacing, contrast, and focus states consistent.

## Why Lucide is the default

Lucide is a clean, outline-style set that covers most common needs. In shadcn/ui, Lucide is the default because it is:

- **Lightweight and tree-shakable:** Only the icons you use end up in your bundle.
- **Consistent:** Same grid, same stroke style, easy to theme.
- **Well supported:** Good coverage for app and dashboard work.

Because the shadcndesign.com kit uses Lucide in Figma, what designers see in the file is what developers render in code. That keeps handoff calm: the same names, the same look, and fewer surprises.

**Good use cases:** navigation, toolbars, lists, menus, settings, empty states, and small inline cues inside forms.

**Watch out for:** Lucide is outline-only. If your brand often flips between outline and solid states for selected vs unselected, you may want a set that has both styles for the same glyph.

## Picking the right icon library (Figma and code)

If you're choosing a set for a new project, use three simple checks:

1. **Coverage:** Is the library broad enough for your screens today and six months from now?
2. **Craft and consistency:** Are shapes, strokes, and grids uniform so the UI feels stable?
3. **Brand fit:** Does the style match your product's tone, from marketing pages to complex screens?

### Why this matters

- A single, high-quality library keeps the UI consistent.
- You avoid mid-project rework or custom icon hunts.
- Good icons pay back in polish, speed, and lower design cost.

**Tip for mixed surfaces:** If you must split styles, keep product UI on one set and marketing on another. Do not mix on the same surface.

## How to install icons from their official libraries

Below are quick install notes for common choices. Always import only the icons you actually use.

### Lucide (default in shadcn/ui + shadcndesign Figma)

**Install:** `npm i lucide-react`

**Import pattern:** `import { Camera } from "lucide-react"`

**Good to know:** Outline-only; supports size, color (inherits currentColor), and strokeWidth.

### Heroicons (outline + solid pairs)

**Install:** `npm i @heroicons/react`

**Import pattern:**

- Outline: `import { CameraIcon } from "@heroicons/react/24/outline"`
- Solid: `import { CameraIcon as CameraSolid } from "@heroicons/react/24/solid"`

**Good to know:** Great for toggling states (outline ↔ solid) with a matched style.

### Radix Icons (product UI, tight grids)

**Install:** `npm i @radix-ui/react-icons`

**Import pattern:** `import { Cross1Icon } from "@radix-ui/react-icons"`

**Optional a11y helper:** `npm i @radix-ui/react-accessible-icon`

**Good to know:** Crisp in dense apps; pair with AccessibleIcon for easy labeling.

### Tabler Icons (large outline set)

**Install:** `npm i @tabler/icons-react`

**Import pattern:** `import { IconCamera } from "@tabler/icons-react"`

**Good to know:** Consistent outlines and broad coverage.

### Phosphor (multiple weights + fills)

**Install:** `npm i phosphor-react`

**Import pattern:** `import { Camera } from "phosphor-react"`

**Good to know:** Switch weights (thin → bold) and fills for expressive states.

**Team hygiene:** Keep a short doc that lists the approved library, icon sizes per control, stroke rules, and where icon files live in the repo. Import icons individually so builds stay lean.

## Customizing size, stroke, and color

### Size

Stick to a small scale that matches your type and spacing, for example: 14, 16, 18, 20, 24.

Buttons and inputs should have a default icon size per size variant.

### Stroke width

- Use one default stroke width per surface.
- Go slightly thicker for tiny icons so they stay readable (where the library supports stroke width).

### Color

- Let icons inherit `currentColor` from text. Theme with tokens like `text-muted-foreground`, `text-primary`, or `text-destructive`.
- Rely on your disabled and error tokens for states.
- Test dark mode early so outlines hold up.

**Accessibility reminder:** Color is not the only cue. Pair with labels or state changes.

## Icons inside buttons

### Position

- **Leading icon** for verbs like Add, Edit, and Download.
- **Trailing icon** for "go to" or "open" actions.

### Spacing

One spacing token between icon and text. Same rule across sizes.

### States

- Icon color follows button state.
- If you show a Spinner, hide the regular icon during loading.

### Icon-only

Add a tooltip and an accessible label.

## Icons inside input groups

### Common patterns

- **Prefix:** search, currency, units, URL.
- **Suffix:** clear, copy, reveal password, calendar, dropdown.

### Fit and flow

- Align vertically with text.
- Keep left and right padding stable so text does not jump when icons appear.

### Focus and error

- Icon color should follow focus and error tokens.
- If the icon is clickable, make the hit area large enough to tap.

## Keeping Figma and code in sync

Because shadcndesign.com uses Lucide and shadcn/ui defaults to Lucide, the Figma-to-code path is smooth:

- Use the same icon names in designs and code.
- Share a size map and stroke rule.
- Document defaults for buttons and inputs.
- If you adopt a second set for a special surface, mirror that choice in both Figma and code.

## Integrating custom icons into the shadcndesign.com Figma kit

If you want a different set in Figma while still using shadcn/ui, there are two easy paths. Both keep your design workflow clean and organized.

### Method 1: Manual integration (simple and direct)

1. Prepare SVG icons, preferably stroke-based to match Lucide's look.
2. Open the shadcn/ui kit file in Figma and go to the Icons page.
3. Create a new frame named "Custom Icons".
4. Import your SVGs into that frame.
5. Select them all and click "Create multiple components".

Now your icons live alongside the kit with clear naming and component structure.

### Method 2: Use Figma's Library feature (best for teams)

**Requires Figma Pro/Org**

1. Publish your custom icons as a Team Library in Figma.
2. In the shadcn UI Kit file, enable that library.
3. Your icons appear in the Assets panel and drop into designs just like the default set.

**Why do this:**

- Designers can swap icons without breaking components.
- You keep a single source of truth and can update icons in one place.
- It mirrors how engineers think about approved resources.

### If you need a one-off icon

Prefer staying within your chosen library. If you truly need a single glyph from another set, install that library via npm, import just the one icon, and document the exception. If one-offs become common, switch the whole surface (e.g., an entire feature area) to a single alternative set and mirror that choice in Figma using one of the methods above.

## Performance and maintenance

- Import only the icons you use.
- Reuse the same glyph for the same meaning across the app.
- Avoid name collisions by aliasing imports if needed.
- Test small sizes, dense tables, and dark mode for legibility.

## Accessibility basics

- **Decorative icons:** Hide them from screen readers so they do not add noise.
- **Interactive icons:** Make sure the control has a clear label, visible or accessible.
- **Contrast:** Follow your token system so icons pass in light and dark themes.
- **State clarity:** Selected and error states should be clear without relying only on color.

## Simple team checklist

- Default to Lucide for product UI to match shadcn/ui and the shadcndesign.com kit.
- When switching sets, install from the official npm package and import icons individually; avoid third-party registries.
- Define a shared size and stroke rule and apply it everywhere.
- Let icons inherit color and theme with tokens.
- Document button and input icon patterns so spacing and states stay consistent.
- If adopting a second set, mirror it in both Figma and code, and use Figma libraries for scale.
- Add tooltips and labels for icon-only controls.

## Closing thoughts

Icons should be quiet helpers, not the star. With shadcn/ui and the shadcndesign.com Figma kit, the default path is simple: stick with Lucide, keep sizes and tokens tight, and place icons where they add clarity. If you need something different, integrate your set into Figma using manual components or a Team Library, and add the library to code from its official npm package. Pick once, document it, and keep the look steady. That is how you ship calm, professional UI without wrestling with icons every sprint.
