Button
BetaLa acción principal de una interfaz. Cuatro estilos, cuatro tamaños, dos radios.
import { Button } from "@/registry/ds/button";
export default function ButtonBasic() {
return <Button>Inscribirme</Button>;
}Playground
Configurá el botón y copiá el snippet — el código se genera desde el mismo estado que renderiza el preview.
Variant
Size
Radius
Icono
Label
<Button>Inscribirme</Button>Jerarquía de estilos
Cada sección de una página tiene un solo Fill (la acción principal). El resto acompaña: Stroke para secundarias fuertes, Tonal para secundarias suaves, Text para terciarias y links.
import { Button } from "@/registry/ds/button";
export default function ButtonVariants() {
return (
<div className="flex flex-wrap items-center gap-4">
<Button variant="fill">Fill</Button>
<Button variant="stroke">Stroke</Button>
<Button variant="tonal">Tonal</Button>
<Button variant="text">Text</Button>
</div>
);
}Tamaños
import { Button } from "@/registry/ds/button";
export default function ButtonSizes() {
return (
<div className="flex flex-wrap items-end gap-4">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra large</Button>
</div>
);
}Radius
El radio lo decide el contexto de la página, no el gusto: Full para superficies de marketing y vida estudiantil, Semi para lo institucional. Nunca mezcles radios dentro de una misma sección.
import { Button } from "@/registry/ds/button";
export default function ButtonRadius() {
return (
<div className="flex flex-wrap items-center gap-4">
<Button radius="full">Full — marketing</Button>
<Button radius="semi">Semi — institucional</Button>
</div>
);
}Con iconos
import { Button } from "@/registry/ds/button";
import { ArrowUpRight, Plus, Search } from "@/registry/ds/icons";
export default function ButtonIcons() {
return (
<div className="flex flex-wrap items-center gap-4">
<Button iconLeft={<Plus />}>Nueva materia</Button>
<Button variant="stroke" iconRight={<ArrowUpRight />}>
Ver programa
</Button>
<Button variant="tonal" iconOnly={<Search />} aria-label="Buscar" />
</div>
);
}Cuándo usarlo
- Sí — para acciones: enviar, inscribirse, confirmar, abrir un flujo.
- Sí — icon-only para acciones de utilidad reconocibles (buscar, cerrar),
siempre con
aria-label. - No — para navegar a otra página dentro del contenido: eso es un link
(
variant="text"existe justamente para esa zona gris). - No — más de un Fill por sección; si todo es principal, nada lo es.
Accesibilidad
- El focus ring (
Primary/8, 2px) viene incluido — no lo quites ni lo tapes. disabledbaja la opacidad a 0.38 y bloquea el pointer; si la acción puede volver a habilitarse, explicá cómo cerca del botón.- En icon-only el
aria-labeles obligatorio.
Props
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
variant | "fill" | "stroke" | "tonal" | "text" | "fill" | Jerarquía visual del botón. |
size | "sm" | "md" | "lg" | "xl" | "md" | Altura 32 / 40 / 48 / 64 px, con tipografía y padding acordes. |
radius | "full" | "semi" | "full" | Full = pill; Semi usa el radius token del tamaño (6–12 px). |
iconLeft | ReactNode | — | Icono antes del label. |
iconRight | ReactNode | — | Icono después del label. |
iconOnly | ReactNode | — | Solo icono; requiere aria-label. Oculta el label. |
disabled | boolean | false | Opacidad 0.38 + pointer-events bloqueados. |