Icon
Un ícono de lucide con los tamaños, los tonos y la semántica del sistema: decoración por defecto, imagen con nombre si tiene label.
import { Icon } from "sebs7n-ui/icon"Ejemplos
Tamaños
16, 20 y 24px: los altos de línea del texto del sistema. El trazo escala con el tamaño, como en lucide.
import { Icon } from "sebs7n-ui/icon"
import { SettingsIcon } from "lucide-react"
function Tamanos() {
return (
<div className="flex items-end gap-6">
<div className="flex flex-col items-center gap-2">
<Icon icon={SettingsIcon} size="sm" />
<span className="text-footnote text-label-secondary">sm · 16</span>
</div>
<div className="flex flex-col items-center gap-2">
<Icon icon={SettingsIcon} size="md" />
<span className="text-footnote text-label-secondary">md · 20</span>
</div>
<div className="flex flex-col items-center gap-2">
<Icon icon={SettingsIcon} size="lg" />
<span className="text-footnote text-label-secondary">lg · 24</span>
</div>
</div>
)
}Tonos
`current` hereda del texto y es el que va casi siempre. Los otros son para un ícono que habla solo.
import { AlertTriangleIcon, CheckCircle2Icon, SearchIcon, SettingsIcon, SparklesIcon, XCircleIcon } from "lucide-react"
import { Icon } from "sebs7n-ui/icon"
function Tonos() {
return (
<div className="grid grid-cols-4 gap-4 sm:grid-cols-7">
{(
[
["current", SparklesIcon],
["muted", SearchIcon],
["subtle", SettingsIcon],
["brand", SparklesIcon],
["success", CheckCircle2Icon],
["warning", AlertTriangleIcon],
["danger", XCircleIcon],
] as const
).map(([tone, icon]) => (
<div className="flex flex-col items-center gap-2" key={tone}>
<Icon icon={icon} size="lg" tone={tone} />
<span className="text-footnote text-label-secondary">{tone}</span>
</div>
))}
</div>
)
}Al lado de un texto
Sin `label`: el texto ya lo dice. El ícono va del mismo color que la palabra, así que el tono queda en `current`.
import { AlertTriangleIcon, CheckCircle2Icon, DownloadIcon, PlusIcon, SettingsIcon } from "lucide-react"
import { Badge } from "sebs7n-ui/badge"
import { Button } from "sebs7n-ui/button"
function ConTexto() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button>
<PlusIcon />
Nueva factura
</Button>
<Button variant="secondary">
<DownloadIcon />
Exportar
</Button>
<Button size="icon-md" variant="ghost" aria-label="Configuración">
<SettingsIcon />
</Button>
<Badge color="green">
<CheckCircle2Icon />
Pagada
</Badge>
<Badge color="amber">
<AlertTriangleIcon />
Vence hoy
</Badge>
</div>
)
}Con nombre accesible
Cuando el ícono es la única señal —no hay palabra al lado—, `label` lo vuelve una imagen con nombre.
import { AlertTriangleIcon, CheckCircle2Icon, XCircleIcon } from "lucide-react"
import { Icon } from "sebs7n-ui/icon"
function ConNombre() {
const filas = [
["Factura 0012", "Pagada", CheckCircle2Icon, "success"],
["Factura 0013", "Vence en 3 días", AlertTriangleIcon, "warning"],
["Factura 0014", "Rechazada", XCircleIcon, "danger"],
] as const
return (
<ul className="flex w-full max-w-sm flex-col divide-y divide-gray-400 rounded-surface border border-separator bg-surface">
{filas.map(([nombre, estado, icon, tone]) => (
<li className="flex items-center justify-between gap-3 px-4 py-3 text-callout" key={nombre}>
<span className="text-label">{nombre}</span>
<Icon icon={icon} label={estado} tone={tone} />
</li>
))}
</ul>
)
}Dentro de un Input
Un ícono a la izquierda con padding en el input. `muted` para que no compita con el texto.
import { Icon } from "sebs7n-ui/icon"
import { Input } from "sebs7n-ui/input"
import { SearchIcon } from "lucide-react"
function EnUnInput() {
return (
<div className="relative w-full max-w-sm">
<Icon className="pointer-events-none absolute top-1/2 left-3 -translate-y-1/2" icon={SearchIcon} size="sm" tone="muted" />
<Input aria-label="Buscar clientes" className="pl-9" placeholder="Buscar clientes…" />
</div>
)
}Estado vacío
`EmptyState` ya pone el cuadrito y el `aria-hidden`: se le pasa el ícono sin tamaño.
import { Button } from "sebs7n-ui/button"
import { EmptyState } from "sebs7n-ui/empty-state"
import { InboxIcon, MailIcon } from "lucide-react"
function EnUnEstadoVacio() {
return (
<EmptyState
action={
<Button size="sm">
<MailIcon />
Enviar recordatorio
</Button>
}
className="w-full max-w-md"
description="Cuando un cliente te escriba, va a aparecer acá."
icon={<InboxIcon />}
title="Sin mensajes"
/>
)
}Cambio de estado
Dos íconos que se reemplazan con un cruce, dentro de un `startTransition`: el navegador hace la animación, no JavaScript.
import { BellIcon, BellRingIcon } from "lucide-react"
import { Button } from "sebs7n-ui/button"
import { Icon } from "sebs7n-ui/icon"
import { startTransition, useState, ViewTransition } from "react"
function CambioDeEstado() {
const [activas, setActivas] = useState(false)
return (
<Button
aria-pressed={activas}
onClick={() => startTransition(() => setActivas((valor) => !valor))}
variant="secondary"
>
{activas ? (
<ViewTransition key="on" enter="icon-in" exit="icon-out" default="none">
<Icon icon={BellRingIcon} tone="brand" />
</ViewTransition>
) : (
<ViewTransition key="off" enter="icon-in" exit="icon-out" default="none">
<Icon icon={BellIcon} />
</ViewTransition>
)}
{activas ? "Notificaciones activas" : "Activar notificaciones"}
</Button>
)
}Animados
Las utilidades de Tailwind alcanzan: `animate-spin` para esperar, `animate-pulse` para «hay algo nuevo». Con `prefers-reduced-motion` se quedan quietos.
import { Button } from "sebs7n-ui/button"
import { Icon } from "sebs7n-ui/icon"
import { InfoIcon, Loader2Icon, Trash2Icon } from "lucide-react"
function Animados() {
return (
<div className="flex flex-wrap items-center gap-6">
<span className="inline-flex items-center gap-2 text-callout text-label-secondary">
<Icon className="animate-spin motion-reduce:animate-none" icon={Loader2Icon} />
Sincronizando
</span>
<span className="inline-flex items-center gap-2 text-callout text-label-secondary">
<Icon className="animate-pulse motion-reduce:animate-none" icon={InfoIcon} tone="brand" />
Hay una versión nueva
</span>
<Button variant="destructive">
<Icon className="transition-transform duration-150 group-hover:-rotate-12" icon={Trash2Icon} />
Borrar
</Button>
</div>
)
}Props
Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».
Icon
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
icon* | LucideIcon | — | El componente de lucide: icon={SearchIcon}. Va como referencia, no como elemento. |
label | string | — | Nombre accesible. Con él, role="img"; sin él, aria-hidden. |
size | "sm" | "md" | "lg" | "md" | sm 16px · md 20px · lg 24px. |
tone | "brand" | "success" | "warning" | "subtle" | "current" | "muted" | "danger" | "current" | current (hereda) · muted · subtle · brand · success · warning · danger. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
Teclado
- —
- No es interactivo. Si se puede apretar, va adentro de un
Button.
Accesibilidad
- Sin
labeles decoración:aria-hidden="true"yfocusable="false", así ni el lector ni Tab lo encuentran. Es lo correcto cuando al lado hay un texto que dice lo mismo. - Con
labelesrole="img"con nombre. Es obligatorio cuando el ícono es la única señal: un check de «pagada» sin la palabra al lado. - Los tonos de estado (
success,warning,danger) usan el 900 de su familia, que llega a 4,5:1 sobre la superficie en los dos temas. Pero el color solo no informa: acompañalo conlabelo con texto. - Sin
"use client": sirve en un Server Component.
Reglas de uso
- No reemplaza a lucide en los componentes del paquete.
Button,Badge,SidebarItemyEmptyStateya dimensionan el<svg>que reciben: ahí va el ícono de lucide pelado (<PlusIcon />).Icones para el ícono suelto —en un texto, en una celda, en un input—. tone="current"casi siempre. Un ícono al lado de una palabra es de la misma tinta que la palabra; el tono propio es para el que habla solo.- Un tamaño por contexto:
sm(16) concopy-14y botones chicos,md(20) concopy-16e ítems de lista,lg(24) con títulos y estados vacíos. No hayxl: un ícono más grande que 24px es una ilustración. - Para animar, las utilidades de Tailwind (
animate-spin,animate-pulse,transition-transform), siempre conmotion-reduce:animate-none. Para cambiar un ícono por otro,<ViewTransition>conkey: el cruce lo hace el navegador. - El catálogo completo, con búsqueda, está en [Iconos](/docs/iconos).