Botón
Lanza una acción o lleva al siguiente paso. Un solo botón principal por grupo de acciones.
Landing y portal
Las dos superficies usan las mismas clases, definidas en public/site/button.css. En la landing se escriben a mano; en el portal las pone el componente Button.
Principal y secundario
<a class="button" href="#">Reservar llamada</a>
<a class="button button-outline" href="#">Ver el plan</a>Pequeño
Cabecera y navegación móvil.
<a class="button button-outline button-small" href="#">Área clientes</a>
<a class="button button-small" href="#">Reservar llamada</a>Claro, sobre fondo oscuro
<a class="button button-light button-small" href="#">Reservar llamada</a>Ancho completo
Dentro de la tarjeta del plan.
<a class="button button-block" href="#">Empezar</a>Con icono
<button type="submit" class="button button-small"><span>Preparar email</span><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 13V3M4 7l4-4 4 4"/></svg></button>Del portal: discreto y peligro
<button class="button">Guardar cambios</button>
<button class="button button-ghost">Cancelar</button>
<button class="button button-danger">Eliminar</button>API de clases
| Clase | Qué hace |
|---|---|
button |
Base: relleno --ink, texto --paper, 44 px de alto, texto de 15 px, radio de 12 px. Hover en --ink-hover. |
button-outline |
Secundario: fondo transparente, borde --line-strong; hover en --paper-2. |
button-ghost |
Sin borde ni fondo, texto --ink-2; hover en --paper-2. Acciones terciarias del portal. |
button-subtle |
Fondo --card con borde --line. |
button-danger |
Relleno --danger, texto blanco. Solo para acciones destructivas. |
button-light |
Para fondos oscuros: relleno --paper, texto --ink. |
button-small |
36 px de alto, texto de 14 px, radio de 10 px. |
button-block |
Ocupa todo el ancho de su contenedor. |
Portal
Button y ButtonLink, en src/components/ui/button.tsx. Traducen sus props a las clases de button.css: variant="outline" → button-outline, size="sm" → button-small. className se añade al final y las utilidades de Tailwind (w-full, márgenes) pueden ajustarlo, porque el botón está en la capa components.
import { Button, ButtonLink } from '@/components/ui';
<Button>Guardar cambios</Button>
<Button variant="ghost">Cancelar</Button>
<Button variant="danger">Eliminar</Button>
<ButtonLink href="/admin/clients/new" size="sm">Nuevo cliente</ButtonLink><button class="button">Guardar cambios</button>
<button class="button button-ghost">Cancelar</button>
<a href="#" class="button button-small">Nuevo cliente</a>Props
| Prop | Valores | Por defecto |
|---|---|---|
variant |
primary, outline, ghost, subtle, danger |
primary |
size |
sm (36 px, 14 px, radio de 10 px), md (44 px, 15 px, radio de 12 px) |
md |
type |
button, submit, reset |
button |
Cuándo usarlo
- Para una acción: reservar una llamada, empezar la suscripción, enviar un formulario, guardar cambios.
- Para ir a un destino clave cuando ese destino es la acción del bloque, como «Área clientes».
Cuándo no
- Dentro de un párrafo o una lista: usa el enlace de texto.
- Para cambiar de vista dentro de la misma página: usa pestañas.
Reglas
| Regla | Cómo se comprueba |
|---|---|
Un solo botón relleno por grupo de acciones. El secundario es outline; ghost para acciones terciarias. |
En cada grupo hay como mucho un .button sin modificador de variante. |
Sobre fondo night, el botón es button-light. |
Ningún .button relleno dentro de un bloque con fondo --night. |
| La etiqueta es un verbo y su objeto, corta y aprobada. | Los textos salen del diccionario i18n; no se reescriben sin petición de Andrés. |
| El icono va después del texto, a 16 px y con trazo de 1,6. | El svg es el último hijo y lleva aria-hidden="true". |
| Altura mínima de 44 px; 36 px en la variante pequeña. | min-height de .button y .button-small. |
Antipatrones
- Doble principal: dos botones rellenos uno al lado del otro.
- Acento como relleno:
--accentes para el foco y la selección, no para botones. - Sinónimos de clase: no existen
.btn,.button-primaryni.button-secondary. Usa solo las clases de la API. - Botón como enlace de párrafo: un botón en mitad de un texto rompe la lectura.
Accesibilidad
<a>cuando navega y<button type="button">otype="submit"cuando actúa.- El foco visible es global: contorno de 2 px en
--accent, separado 3 px en la landing y 2 px en el portal. - Los enlaces externos (Calendly) llevan
target="_blank"yrel="noopener noreferrer". - En el portal,
disabledbaja la opacidad al 50 % y desactiva el puntero;SubmitButtonañadearia-busymientras envía.
Una sola fuente
Desde el 11 de octubre de 2026 la landing y el portal comparten public/site/button.css (imandresochoa/designloop#11). Cualquier cambio del botón se hace en ese archivo y llega a las dos superficies.
Tokens que usa
Enlace con producción
| Superficie | Fuente | Estado | Huella | Revisada en |
|---|---|---|---|---|
| Landing | public/site/button.css .button .button-outline .button-ghost .button-subtle .button-danger .button-light .button-small .button-block | Sincronizado | 2ba69fbd2d963caa | e89e520 |
| Portal de clientes | src/components/ui/button.tsx | Sincronizado | 9c0b89d35ff98960 | e89e520 |
Producción en el commit 455e861 (2026-10-13). Sync del 2026-10-13.
Relacionados
componentes/boton · Actualizado el 2026-10-11