Ir al contenido

Componentes · Ola 1 · Acciones

Button

Dispara una acción o, como enlace, lleva a otra página con el mismo aspecto. La acción principal es luz blanca, también dentro de los productos: el acento del producto no toca los botones.

import { Button } from '@archeblack/ui'; import { IconPlus } from '@archeblack/ui/icons';

Ejemplos

Variantes

primary para la acción principal, secondary (por defecto) para las demás, ghost para las de bajo peso, danger para las destructivas y link dentro de un texto.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
</script>

<Button variant="primary">Crear proyecto</Button>
<Button>Invitar</Button>
<Button variant="ghost">Cancelar</Button>
<Button variant="danger">Eliminar</Button>
<Button variant="link">Ver documentación</Button>

Tallas

sm en tablas y barras densas, md en la interfaz y lg en formularios de una sola acción. Una fila de primary, una de secondary y una de solo ícono, cada una en las tres tallas con el mismo contenido. El ícono mide 16 px en sm y md, y 20 px en lg.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
	import { IconPlus } from '@archeblack/ui/icons';
</script>

<!--
	Una fila por variante (y una de solo ícono) con sus tres tallas y el mismo contenido: solo
	cambia la talla. El ícono mide 16 px en sm y md, y 20 px en lg.
-->
<div style:display="grid" style:justify-items="center" style:gap="var(--arche-spacing-4)">
	<div
		style:display="flex"
		style:flex-wrap="wrap"
		style:align-items="center"
		style:gap="var(--arche-spacing-3)"
	>
		<Button variant="primary" size="sm">Crear</Button>
		<Button variant="primary">Crear</Button>
		<Button variant="primary" size="lg">Crear</Button>
	</div>
	<div
		style:display="flex"
		style:flex-wrap="wrap"
		style:align-items="center"
		style:gap="var(--arche-spacing-3)"
	>
		<Button size="sm">Abrir</Button>
		<Button>Abrir</Button>
		<Button size="lg">Abrir</Button>
	</div>
	<div
		style:display="flex"
		style:flex-wrap="wrap"
		style:align-items="center"
		style:gap="var(--arche-spacing-3)"
	>
		<Button size="sm" icon={IconPlus} aria-label="Agregar" />
		<Button icon={IconPlus} aria-label="Agregar" />
		<Button size="lg" icon={IconPlus} aria-label="Agregar" />
	</div>
</div>

Con íconos

iconStart e iconEnd acompañan al texto. icon hace un botón de solo ícono, con aria-label obligatorio.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
	import { IconArrowRight, IconDots, IconEdit, IconPlus, IconX } from '@archeblack/ui/icons';
</script>

<Button variant="primary" iconStart={IconPlus}>Nuevo proyecto</Button>
<Button iconEnd={IconArrowRight}>Continuar</Button>
<!-- Solo ícono: aria-label es obligatorio. -->
<Button variant="ghost" icon={IconDots} aria-label="Más acciones" />
<Button icon={IconEdit} aria-label="Editar" />
<Button variant="ghost" size="sm" icon={IconX} aria-label="Cerrar" />

En curso

loading muestra el indicador en lugar del ícono, ignora los clics y conserva el foco. El texto no cambia, así el botón no salta de ancho. Pulsa «Guardar cambios» para verlo.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
	import { IconDeviceFloppy, IconRefresh } from '@archeblack/ui/icons';

	let saving = $state(false);

	function save() {
		saving = true;
		setTimeout(() => (saving = false), 2500);
	}
</script>

<!--
	El indicador reemplaza al ícono y el texto queda igual, así el botón no cambia de ancho.
	aria-busy avisa que la acción está en curso y el botón conserva el foco.
-->
<Button variant="primary" iconStart={IconDeviceFloppy} loading={saving} onclick={save}>
	Guardar cambios
</Button>
<Button loading>Exportando</Button>
<Button variant="ghost" icon={IconRefresh} aria-label="Actualizando" loading />

Deshabilitado

Todas las variantes se apagan igual, salvo link, que no tiene caja: fondo hover translúcido, sin borde y texto text-disabled. Como el fondo es luz translúcida, sobre cualquier capa (la página, una tarjeta o un diálogo en surface-overlay) el botón queda un paso más claro que ella y no parece un hueco.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
</script>

<Button variant="primary" disabled>Publicar</Button>
<Button disabled>Duplicar</Button>
<Button variant="ghost" disabled>Descartar</Button>
<Button variant="danger" disabled>Eliminar</Button>
<Button variant="link" disabled>Ver registro</Button>

Como enlace

Con href se dibuja un <a> con el mismo aspecto.

Ver las props Accesibilidad

El botón de solo ícono exige un nombre. Qué evitar

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
	import { IconExternalLink } from '@archeblack/ui/icons';
</script>

<!-- Con href es un <a>: navega, se abre en otra pestaña y se lee como enlace. -->
<Button href="#props" variant="primary">Ver las props</Button>
<Button href="#accessibility" iconEnd={IconExternalLink}>Accesibilidad</Button>
<p>
	El botón de solo ícono exige un nombre. <Button href="#avoid" variant="link">Qué evitar</Button>
</p>

Grupo de acciones

El pie típico de un formulario: una sola acción primaria, al final.

Svelte
<script lang="ts">
	import { Button } from '@archeblack/ui';
	import { IconSend } from '@archeblack/ui/icons';
</script>

<!-- La acción principal va al final y es la única primaria del grupo. -->
<div style:display="flex" style:flex-wrap="wrap" style:gap="var(--arche-spacing-2)">
	<Button variant="ghost">Cancelar</Button>
	<Button>Guardar borrador</Button>
	<Button variant="primary" iconEnd={IconSend}>Publicar</Button>
</div>

Props

Props de Button
PropDescripción
variant? 'primary' | 'secondary' | 'ghost' | 'danger' | 'link' Por defecto 'secondary'primary es la acción principal (una por vista); secondary, las demás; ghost, las de bajo peso; danger, las destructivas; link, una acción con aspecto de enlace.
size? 'sm' | 'md' | 'lg' Por defecto 'md'Alto de 1,75 rem (sm, texto de 13 px), 2,25 rem (md) o 2,75 rem (lg). Crece con la fuente del usuario. Los íconos miden 16 px en sm y md, y 20 px en lg.
children? Snippet El texto del botón. Es obligatorio salvo en el botón de solo ícono.
iconStart? IconGlyph Ícono antes del texto, decorativo. Mientras carga, el indicador giratorio ocupa su lugar.
iconEnd? IconGlyph Ícono después del texto, decorativo.
icon? IconGlyph Botón de solo ícono: un cuadrado del alto de la talla. No admite texto, y los tipos exigen aria-label.
aria-label? string Nombre accesible. Obligatorio con icon; con texto no hace falta.
loading? boolean Por defecto falseAcción en curso: indicador giratorio, aria-busy="true" y aria-disabled="true". Ignora clics y teclado sin sacar el foco, y conserva el aspecto de su variante.
disabled? boolean Por defecto falseComo botón usa el atributo nativo disabled. Como enlace se queda sin href, con role="link" (o el role que pases) y aria-disabled="true". Se ve con fondo hover translúcido, sin borde ni brillo, y texto text-disabled.
href? string Con href se dibuja un <a> con el mismo aspecto. Admite target, rel, download y el resto de atributos de enlace.
type? 'button' | 'submit' | 'reset' Por defecto 'button'Solo en el <button>. Para enviar un formulario, type="submit".
class? ClassValue Clases del producto; se suman a arche-button.
...rest HTMLButtonAttributes | HTMLAnchorAttributes Cualquier otro atributo va al <button> o al <a>, incluidos los eventos como onclick.

Accesibilidad

  • Es un <button> nativo con type="button" por defecto: no envía un formulario por accidente, y Enter y espacio lo activan.
  • Con href es un <a>: se lee como enlace y navega. Usa href para ir a otro lugar y el botón para hacer algo.
  • El botón de solo ícono exige aria-label (TypeScript lo rechaza sin él). El ícono es decorativo: el nombre va en el botón.
  • Mientras carga, aria-disabled en vez de disabled: el botón no pierde el foco y el lector de pantalla lo sigue encontrando. aria-busy indica que la acción está en curso; anuncia el resultado con un mensaje de estado. Si cambias el texto («Guardando…»), que el ancho del botón no salte.
  • El indicador giratorio se detiene con movimiento reducido; el texto y aria-busy siguen diciendo que la acción está en curso.
  • El foco es el anillo de Arche, y su halo se mantiene con el puntero encima: el brillo del hover se suma, no lo reemplaza. En colores forzados, cada botón con caja muestra su borde con el color del sistema y el inactivo pasa a GrayText.
  • El texto de todas las variantes supera 4,5:1. El texto deshabilitado está exento, por eso un botón deshabilitado necesita un motivo visible cerca.

Qué evitar

  • Varios botones primary en la misma vista. Uno solo para la acción principal; las demás, secondary o ghost.
  • Un botón que navega (onclick con goto). Pasa href: se dibuja un <a> y funcionan abrir en otra pestaña y copiar el enlace.
  • disabled mientras se guarda. loading: el foco se queda en el botón y el usuario sabe que la acción está en curso.
  • Un botón deshabilitado sin explicación. Di al lado qué falta para habilitarlo, o déjalo habilitado y valida al enviar.
  • Un ícono suelto dentro de children o un SVG propio. iconStart, iconEnd o icon, con un ícono de @archeblack/ui/icons.
  • danger para acciones que no destruyen nada. Resérvalo para eliminar o revocar, con un texto que diga qué se pierde.