Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Instala Lucide React, importa iconos individuales por nombre y personalízalos con props o clases de Tailwind. Cada ícono es un módulo separado, así que tu bundle solo incluye los iconos que realmente usas.
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>
);
}Una barra de herramientas de botones de ícono con estados al pasar el cursor y etiquetas de accesibilidad:
// 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, pero también disponible como módulo independiente en lucide-react/dist/esm/icons/{icon-name}.currentColor.className, style, onClick y atributos ARIA.Renderizado dinámico de ícono desde un nombre de cadena:
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" />Nota: Importar el objeto icons completo derrota el tree-shaking. Solo usa renderizado dinámico cuando realmente lo necesites (p. ej., selección de ícono impulsada por CMS).
Componente envolvente de ícono 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 tipificar componentes de iconos pasados como props.LucideProps, que extiende SVGProps<SVGSVGElement> con size, color, strokeWidth y absoluteStrokeWidth.icons se tipifica como Record<string, LucideIcon>, permitiendo búsquedas dinámicas type-safe.import type { LucideIcon, LucideProps } from "lucide-react";
// Tipifica una prop de ícono
interface Props {
icon: LucideIcon;
iconProps?: LucideProps;
}lucide-react con importaciones de barril como import * as icons agrupará cada ícono (más de 1,400 SVGs). Siempre usa importaciones nombradas para compilaciones de producción.color establece el atributo SVG stroke, no fill. Los iconos Lucide se basan en trazo, así que fill no tiene efecto visible en la mayoría de iconos.className para establecer color vía Tailwind (p. ej., text-blue-500), no establezca también la prop color, ya que la prop explícita anula currentColor.size establece tanto width como height simultáneamente. Para tamaño no cuadrado, usa las props width y height individualmente.icons[name] no proporcionan validación en tiempo de compilación de que el nombre del ícono existe. Considera construir una lista blanca para escenarios impulsados por CMS.| Enfoque | Ventajas | Desventajas |
|---|---|---|
| Lucide React | Tree-shaking excelente, conjunto grande de iconos, mantenimiento activo | El estilo solo de trazo puede no encajar en todos los diseños |
| React Icons | Múltiples familias de iconos en un paquete | Tamaño de instalación más grande, APIs inconsistentes entre familias |
| Heroicons | Proyecto oficial de Tailwind Labs, gran integración de Tailwind | Conjunto de iconos más pequeño (alrededor de 300 iconos) |
| Componentes SVG personalizados | Control total del diseño, cero dependencias | Mantenimiento manual, sin descubrimiento de iconos |
npm install lucide-react
import { Search } from "lucide-react";
export function MyComponent() {
return <Search size={24} className="text-gray-600" />;
}currentColor, que se hereda de la propiedad CSS color del padre.icons completo (import { icons } from "lucide-react") agrupa todos los 1,400+ iconos y derrota el 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} />;Nota: esto importa todos los iconos y desactiva el tree-shaking.
color explícita anula currentColor.text-blue-500) establece currentColor, pero la prop tiene prioridad.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 el atributo stroke, no fill.fill="red" en un ícono de trazo no cambiará su apariencia.size establece tanto width como height al mismo valor.width y height individualmente en lugar de size.import type { LucideIcon, LucideProps } from "lucide-react";
interface Props {
icon: LucideIcon;
iconProps?: LucideProps;
}LucideIcon tipifica el componente en sí; LucideProps extiende SVGProps<SVGSVGElement>.
useState para rastrear qué herramienta está activa.aria-label para lectores de pantalla y aria-pressed para indicar el estado de alternancia.strokeWidth más grueso (2.5 vs 2) y un fondo azul.icons[name] no proporciona validación en tiempo de compilación de que el nombre del ícono existe.undefined.Record<string, LucideIcon>.Revisado por Chris St. John·Última actualización: 19 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥