Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Instale o Lucide React, importe ícones individuais por nome e personalize-os com props ou classes Tailwind. Cada ícone é um módulo separado, então seu bundle inclui apenas os ícones que você realmente usa.
npm install lucide-react// app/components/icon-demo.tsx
"use client";
import { Search, Menu, X, Settings, Bell } from "lucide-react";
export function IconDemo() {
return (
<div className="flex items-center gap-4">
<Search size={24} color="currentColor" strokeWidth={2} />
<Menu size={24} className="text-gray-600" />
<X size={20} className="text-red-500" />
<Settings size={24} strokeWidth={1.5} />
<Bell size={24} className="text-blue-600" />
</div>
);
}Uma barra de ferramentas com botões de ícone, estados de hover e rótulos de acessibilidade:
// app/components/icon-toolbar.tsx
"use client";
import { Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, Link, Image } from "lucide-react";
import { useState } from "react";
interface ToolbarButton {
icon: React.ElementType;
label: string;
action: string;
}
const tools: ToolbarButton[] = [
{ icon: Bold, label: "Bold", action: "bold" },
{ icon: Italic, label: "Italic", action: "italic" },
{ icon: Underline, label: "Underline", action: "underline" },
{ icon: AlignLeft, label: "Align Left", action: "align-left" },
{ icon: AlignCenter, label: "Align Center", action: "align-center" },
{ icon: AlignRight, label: "Align Right", action: "align-right" },
{ icon: Link, label: "Insert Link", action: "link" },
{ icon: Image, label: "Insert Image", action: "image" },
];
export function IconToolbar() {
const [active, setActive] = useState<string | null>(null);
return (
<div className="flex items-center gap-1 rounded-lg border border-gray-200 bg-white p-2">
{tools.map(({ icon: Icon, label, action }) => (
<button
key={action}
onClick={() => setActive(active === action ? null : action)}
aria-label={label}
aria-pressed={active === action}
className={`rounded p-2 transition-colors hover:bg-gray-100 ${
active === action ? "bg-blue-100 text-blue-600" : "text-gray-600"
}`}
>
<Icon size={18} strokeWidth={active === action ? 2.5 : 2} />
</button>
))}
</div>
);
}lucide-react, mas também está disponível como um módulo autônomo em lucide-react/dist/esm/icons/{nome-do-icone}.currentColor.className, style, onClick e atributos ARIA.Renderização dinâmica de ícone a partir de um nome de string:
import { icons } from "lucide-react";
import type { LucideIcon } from "lucide-react";
interface DynamicIconProps {
name: string;
size?: number;
className?: string;
}
export function DynamicIcon({ name, size = 24, className }: DynamicIconProps) {
const IconComponent = icons[name as keyof typeof icons] as LucideIcon | undefined;
if (!IconComponent) {
return null;
}
return <IconComponent size={size} className={className} />;
}
// Uso: <DynamicIcon name="ArrowRight" size={20} className="text-blue-500" />Observação: Importar o objeto icons inteiro anula o tree-shaking. Use a renderização dinâmica apenas quando realmente precisar dela (por exemplo, seleção de ícones controlada por CMS).
Componente wrapper de ícone personalizado:
import type { LucideIcon } from "lucide-react";
interface IconButtonProps {
icon: LucideIcon;
label: string;
onClick: () => void;
variant?: "default" | "danger" | "success";
}
const variantStyles = {
default: "text-gray-600 hover:bg-gray-100",
danger: "text-red-600 hover:bg-red-50",
success: "text-green-600 hover:bg-green-50",
};
export function IconButton({ icon: Icon, label, onClick, variant = "default" }: IconButtonProps) {
return (
<button
onClick={onClick}
aria-label={label}
className={`rounded-lg p-2 transition-colors ${variantStyles[variant]}`}
>
<Icon size={20} />
</button>
);
}LucideIcon para tipar componentes de ícone passados como props.LucideProps, que estende SVGProps<SVGSVGElement> com size, color, strokeWidth e absoluteStrokeWidth.icons é tipado como Record<string, LucideIcon>, permitindo buscas dinâmicas seguras em termos de tipo.import type { LucideIcon, LucideProps } from "lucide-react";
// Tipa uma prop de ícone
interface Props {
icon: LucideIcon;
iconProps?: LucideProps;
}lucide-react com importações de barril como import * as icons agrupará todos os ícones (mais de 1.400 SVGs). Sempre use importações nomeadas para builds de produção.color define o atributo stroke do SVG, não fill. Ícones Lucide são baseados em traço, então fill não tem efeito visível na maioria dos ícones.className para definir a cor via Tailwind (por exemplo, text-blue-500), não defina também a prop color, pois a prop explícita substitui currentColor.size define width e height simultaneamente. Para dimensionamento não quadrado, use as props width e height individualmente.icons[name] não fornecem validação em tempo de compilação de que o nome do ícone existe. Considere criar uma lista de permissões (whitelist) para cenários controlados por CMS.| Abordagem | Prós | Contras |
|---|---|---|
| Lucide React | Excelente tree-shaking, grande conjunto de ícones, manutenção ativa | O estilo apenas com traço pode não se adequar a todos os designs |
| React Icons | Múltiplas famílias de ícones em um único pacote | Tamanho de instalação maior, APIs inconsistentes entre famílias |
| Heroicons | Projeto oficial do Tailwind Labs, ótima integração com Tailwind | Conjunto de ícones menor (cerca de 300 ícones) |
| Componentes SVG personalizados | Controle total do design, zero dependências | Manutenção manual, sem descoberta de ícones |
npm install lucide-react
import { Search } from "lucide-react";
export function MyComponent() {
return <Search size={24} className="text-gray-600" />;
}currentColor, que herda da propriedade color CSS pai.icons inteiro (import { icons } from "lucide-react") agrupa todos os 1.400+ ícones e desabilita o tree-shaking.import { icons } from "lucide-react";
import type { LucideIcon } from "lucide-react";
const IconComponent = icons[name as keyof typeof icons] as LucideIcon | undefined;
if (IconComponent) return <IconComponent size={24} />;Observação: isso importa todos os ícones e desabilita o tree-shaking.
color substitui currentColor.text-blue-500) define currentColor, mas a prop tem precedência.import type { LucideIcon } from "lucide-react";
interface IconButtonProps {
icon: LucideIcon;
label: string;
onClick: () => void;
variant?: "default" | "danger";
}
export function IconButton({ icon: Icon, label, onClick, variant = "default" }: IconButtonProps) {
return (
<button onClick={onClick} aria-label={label}>
<Icon size={20} />
</button>
);
}color controla o atributo stroke, não fill.fill="red" em um ícone de traço não alterará sua aparência.size define width e height com o mesmo valor.width e height individualmente em vez de size.import type { LucideIcon, LucideProps } from "lucide-react";
interface Props {
icon: LucideIcon;
iconProps?: LucideProps;
}LucideIcon tipa o próprio componente; LucideProps estende SVGProps<SVGSVGElement>.
useState para rastrear qual ferramenta está ativa.aria-label para leitores de tela e aria-pressed para indicar o estado do toggle.strokeWidth mais espessa (2,5 vs 2) e um fundo azul.icons[name] não fornece validação em tempo de compilação de que o nome do ícone existe.undefined.Record<string, LucideIcon>.Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥