Tucano v0.37.2

Botón

Nació de lo que los componentes necesitaban por dentro — el "Deshacer" del toast, el "Aplicar" del calendario. En lugar de que cada uno inventara el suyo, todo sale de aquí, y queda disponible para tu proyecto. Son solo clases: un <button> sigue siendo un <button>.

Ejemplos

Variante, tamaño y estado son clases y atributos que se combinan.

Tamaños

is-sm mide 30px, el predeterminado sale de --tuc-control-height e is-lg mide 44px.

Con icono

El <svg> toma el tamaño del botón por sí solo. is-icon lo vuelve cuadrado — y entonces el aria-label es obligatorio.

Ocupado

aria-busy="true" con .tuc-spinner. Haz clic en "Guardar" para ver el cambio.

Desactivado

disabled no recibe clic ni foco; aria-disabled="true" sigue siendo enfocable y anunciado.

Ancho completo

is-block ocupa toda la línea — el botón de un formulario estrecho o de un móvil.

Como enlace

En un <a> la clase quita el subrayado; es lo correcto cuando el botón navega, y no ejecuta una acción.

Cómo usar

tuc-btn y una variante. Sin variante el botón queda transparente, sin borde — la base de la que parten las variantes.

<button type="submit" class="tuc-btn is-primary">Guardar</button>
<button type="button" class="tuc-btn is-outline is-sm">Cancelar</button>
<button type="button" class="tuc-btn is-ghost is-icon" aria-label="Cerrar">
  <svg>...</svg>
</button>
<a class="tuc-btn is-link" href="/help/">Más información</a>

En el formulario de Django

El botón es de la plantilla, no del form. Con type="submit" envía el formulario como siempre.

<form method="post">
  {% csrf_token %}
  {{ form }}
  <a class="tuc-btn is-outline" href="{% url 'customers' %}">Cancelar</a>
  <button type="submit" class="tuc-btn is-primary">Guardar</button>
</form>

En JavaScript

No hay componente que instanciar. Lo que se hace en código es cambiar el estado — por ejemplo, ocupado durante un envío:

const btn = document.querySelector('#save');
btn.setAttribute('aria-busy', 'true');
btn.disabled = true;               // impide el segundo clic
btn.prepend(Object.assign(document.createElement('span'), { className: 'tuc-spinner' }));

// ...cuando termine
btn.removeAttribute('aria-busy');
btn.disabled = false;
btn.querySelector('.tuc-spinner').remove();

Variantes y cuándo usarlas

Una acción principal por área. Las demás ceden peso visual, y la destructiva se distingue por el color.

ClasePara qué
is-primaryAcción principal, en el color de acento (--tuc-accent)
is-outlineAcción secundaria, con borde
is-ghostTerciaria, sin peso visual — acciones dentro de una tabla, barra de herramientas
is-dangerDestructiva, pintada con --tuc-danger-fill
is-linkParece un enlace, se comporta como botón

Por qué el rojo del botón es otro token

--tuc-danger es más claro en modo oscuro, para tener contraste como texto — y un botón pintado con él quedaría pastel con texto blanco. --tuc-danger-fill es el mismo en los dos temas.

Botón y campo tienen la misma altura

Los dos salen de --tuc-control-height — 38px, o 44px en el diseño compacto, donde el área táctil necesita ser mayor. Radio y borde vienen de --tuc-radius-md y --tuc-border-width. Un botón junto a un select queda alineado sin ajustes.

Ocupado y desactivado

Los dos impiden la acción, pero dicen cosas distintas, y por eso se ven distintos.

<button class="tuc-btn is-primary" aria-busy="true" disabled>
  <span class="tuc-spinner"></span> Guardando
</button>

<button class="tuc-btn is-outline" aria-disabled="true">Exportar</button>

Ocupado no es desactivado

El disabled junto al aria-busy impide el segundo clic, pero el atenuado al 50% diría "no disponible" — y el botón está trabajando. Con aria-busy="true" mantiene el color pleno y el cursor de espera. El spinner se mide en em y se pinta con currentColor: dentro del botón ocupa el lugar del icono y sale blanco en un primario, sin variante.

Desactivado muestra el cursor de bloqueo

Nada de pointer-events: none: sin recibir el puntero el elemento no cambia el cursor, y la persona se queda sin señal de que el botón no responde. En un <button disabled> el navegador ya impide el clic. Con aria-disabled="true" el clic sigue llegando a propósito — es el botón que sigue enfocable y anunciado, y quien usa el atributo trata el clic en su propio manejador.

Desactivado tampoco reacciona al hover — cambiar de color sugeriría que todavía funciona — y pierde la sombra. Al pulsarlo, el botón se encoge un poco: en un toque, sin hover, el color por sí solo no confirma que el dedo acertó el objetivo. Con prefers-reduced-motion ese movimiento desaparece.

Teclado y accesibilidad

Es el <button> del navegador: foco, Enter y Espacio vienen gratis. Lo que le toca a la plantilla es elegir el elemento correcto y darle nombre a lo que no tiene texto.

TeclaAcción
TabLlega al botón, con el anillo de foco de los campos; salta el disabled, no el aria-disabled
Enter EspacioActiva el <button>; en un <a class="tuc-btn">, solo Enter

Clases

Solo CSS, sin JavaScript. No escribas un segundo diseño de botón: una acción dentro de una tabla o de un bloque de código también es .tuc-btn, con una clase propia solo para posicionar.

Clase o atributoPara qué
tuc-btnLa base: altura, fuente, radio, foco. Vale en <button> y <a>
is-primary is-outline is-ghost is-danger is-linkVariante
is-sm is-lgTamaño: 30px y 44px; el icono acompaña
is-iconCuadrado, solo icono; se combina con is-sm e is-lg
is-blockOcupa todo el ancho
disabledAtenuado, cursor de bloqueo, sin hover; el navegador bloquea el clic
aria-disabled="true"El mismo diseño, pero enfocable y con el clic llegando
aria-busy="true"Ocupado: color pleno y cursor de espera, incluso con disabled
.tuc-spinner dentroOcupa el lugar y el tamaño del icono
--tuc-btn-iconTamaño del <svg> hijo; cada tamaño de botón define el suyo