Next.js Lucide Icons
Next.js Lucide icons from lucide-react, used straight in server component pages: find an icon, import it by name, size and color it, label icon-only buttons.
A small icon tells people what a link or button does before they read its label: a bell for notifications, a printer to print, a trash can to delete. AdminKit for Next.js draws its icons with Lucide, an open-source set of 2,015 icons on a 24×24 grid. You get them in the free and PRO versions.
Every icon is a React component from the lucide-react package. Import Bell, write <Bell />, and it renders an inline <svg> in the color of the surrounding text.
Icons work in server components, so you don't need "use client" to show one. Pages in the App Router are server components: they render to HTML at build time and have no state. lucide-react adds "use client" to the parts that need it, so you don't have to. Next.js still writes the <svg> into the page's HTML. The icons appear before any JavaScript runs, and your page stays a server component with its metadata export.
Example
import {
Bell,
ChartPie,
CreditCard,
House,
Mail,
MessageSquare,
Settings,
Users,
} from "lucide-react";
import { pageMetadata } from "@/lib/site";
export const metadata = pageMetadata("/projects");
export default function ProjectsPage() {
return (
<div className="d-flex gap-3">
<House />
<Bell />
<Mail />
<MessageSquare />
<Users />
<CreditCard />
<ChartPie />
<Settings />
</div>
);
}Find an icon
Look the icon up on lucide.dev, or open /icons-lucide in the template. That page shows every icon and filters them by name and tag while you type.
The name you find there is in kebab-case. The component is the same name in PascalCase: remove the dashes and capitalize each word.
| Lucide name | Component |
|---|---|
bell | Bell |
chart-pie | ChartPie |
circle-check-big | CircleCheckBig |
message-square | MessageSquare |
A few older names still work as aliases, so Home imports House. Use the current names from lucide.dev, as the template does.
Import only what you use
Import icons one by one, by name:
import { Download, Printer, Send } from "lucide-react";Next.js then ships only those icons to the browser. The rest of the package never reaches your JavaScript, which is what tree shaking means.
The package also has an icons object that holds every icon. The template imports it in one place: src/components/pages/icons/lucide/lucide-icons.tsx, the search list of the Lucide demo page. That component starts with "use client" because the search field keeps state. Next.js splits the JavaScript per route, so the full set loads on that page only. Keep to named imports everywhere else.
Sizes
Every icon gets the lucide class, which AdminKit's CSS sets to 18×18 pixels and a stroke width of 2. lucide-sm makes it 14 pixels and lucide-lg 36 pixels. In a .btn, icons are 14 pixels.
<Bell className="lucide-sm" />
<Bell />
<Bell className="lucide-lg" />Other sizes take a style or a class of your own:
<Bell style={{ width: 24, height: 24 }} />
<Bell style={{ width: 48, height: 48 }} />Don't count on the size and strokeWidth props. They become attributes on the <svg>, and the lucide class overrides those. Use style instead, for example style={{ strokeWidth: 1.5 }}.
Colors
An icon draws in currentColor, the text color of its parent. Bootstrap's text color classes give it a color of its own:
<Bell className="text-primary" />
<Bell className="text-secondary" />
<Bell className="text-success" />
<Bell className="text-danger" />
<Bell className="text-warning" />
<Bell className="text-info" />Icons next to text
Next to a label, give the icon align-middle so it lines up with the text, and me-1 for a little space. The invoice page does this for its Print, Download PDF and Send invoice buttons.
<button type="button" className="btn btn-primary">
<Download className="align-middle me-1" /> Download PDF
</button>Icon-only buttons
Without a label, a screen reader has nothing to say about a button. Put an aria-label on the button that names the action. You don't have to hide the icon: lucide-react gives it aria-hidden="true" unless you pass it an aria-*, role or title prop.
import { Pen, Trash } from "lucide-react";
<button type="button" className="btn btn-light" aria-label="Edit">
<Pen />
</button>
<button type="button" className="btn btn-light" aria-label="Delete">
<Trash />
</button>Pass an icon as a prop
A stat card or a menu item often shows an icon that its parent chooses. How you pass it depends on what kind of component receives it.
A server component can take the icon component itself, typed as LucideIcon. The Analytics dashboard passes icon={Users} to its Stats cards, which have no "use client":
import { DollarSign, type LucideIcon } from "lucide-react";
function StatCard({ icon: Icon, title }: { icon: LucideIcon; title: string }) {
return (
<div className="card">
<div className="card-body">
<Icon className="align-middle" /> {title}
</div>
</div>
);
}
<StatCard icon={DollarSign} title="Income" />;A client component can't take it from a server component page. A component is a function, and a server component can only pass data that Next.js can send to the browser. Pass the rendered icon instead, typed as ReactNode, as the CRM dashboard of AdminKit PRO does with its CrmStatCard:
<CrmStatCard
title="Total customers"
icon={<Users className="align-middle" />}
stat="customers"
/>Between client components, either way works. The sidebar is a client component and reads its menu from src/data/navigation.ts, where each item has an icon such as SlidersVertical.
Accessibility
lucide-reactaddsaria-hidden="true"to an icon, unless you give it anaria-*,roleortitleprop.- A button or link with only an icon needs an
aria-label. The edit and delete links of the tables demo have one. - If an icon means something on its own, without text next to it, add a text alternative: an
aria-labelon the element around it, or a<span className="visually-hidden">with the text.
Related
- React Lucide icons: the same icons in AdminKit for React (Vite)
- Bootstrap 5 Lucide icons: the icons of the HTML version
- Font Awesome icons: the second icon set of AdminKit PRO
- Buttons: buttons with icons
- Lucide icons demo
Last updated on
Treemap chartPro
A Next.js treemap chart for the App Router: an ApexCharts client component in AdminKit PRO that sizes a rectangle per value, with theme colors.
Font AwesomePro
Next.js Font Awesome icons in AdminKit PRO: the Font Awesome 7 Free webfont, loaded by the root layout, as plain markup that works in server components.