Componentes y código
Estados
Por qué un estado de interacción es una variante en Figma y una pseudoclase en CSS, en qué se diferencian active y current, cómo entran los atributos ARIA y por qué DesignToken101 usa un token por estado en lugar de una opacidad.
Última revisión:
Un botón cambia cuando pasas el puntero, cuando lo pulsas y cuando le llega el foco. En Figma, cada uno de esos estados se dibuja. En código no se programa: lo decide el navegador. En esta lección verás esa diferencia, la que hay entre active y current, y por qué DesignToken101 da a cada estado su propio token.
En esta página
- Dos clases de estado
- En Figma, una variante
- En código, el navegador
- Active no es current
- Estados que anuncia ARIA
- Un token por estado
- Lo que te llevas
Dos clases de estado
Un componente puede cambiar por dos motivos distintos:
- Por la interacción: el puntero encima (
hover), el control pulsado (active) o el foco del teclado (focus). Dura lo que dura el gesto. - Por su situación: es la página actual (
current) o una sección abierta (open). Dura hasta que algo cambia en la página.
La diferencia importa porque cada clase de estado se resuelve de una forma en código.
En Figma, una variante
En Figma, los dos se dibujan igual: con una propiedad de variante, que según su ayuda sirve para las variaciones de un componente, como sus estados, tamaños o colores (Figma: Explore component properties). El Button de DesignToken101 tiene tres propiedades de variante, variant, showIcon y state, y por eso dieciséis dibujos: dos variantes, con icono y sin él, por cuatro estados. showIcon es una variante y no un booleano porque el icono no se limita a aparecer: cambia el relleno del botón (en código, ps-400 pe-300 en lugar de px-400). Es la fila "booleano que cambia el aspecto" de El mismo nombre en los dos lados.
Cada dibujo aplica los tokens de su columna en la tabla de anatomía. Así se revisa en Figma el hover o el foco de un control sin programarlo.
En código, el navegador
En código, un estado de interacción no es un prop. Nadie le dice al botón "ahora estás en hover": el navegador lo sabe y aplica los estilos de la pseudoclase correspondiente (:hover, :active, :focus-visible). Por eso, en DesignToken101, state es una propiedad que existe únicamente en Figma.
En Tailwind CSS, cada clase se puede aplicar con una condición añadiendo una variante al principio de su nombre (Tailwind CSS: Hover, focus, and other states). Con las clases que salen de tus tokens, un estado de la tabla recorre este camino:
- state=hover, Variante del componente en Figma
- background/accent/strong/hover, Token de la tabla de anatomía
- hover:bg-accent-strong-hover, Clase de Tailwind CSS
- :hover, Lo aplica el navegador
El foco tiene una particularidad: en DesignToken101 no usa una clase de color, sino el anillo de dos tokens que viste en El foco, con :focus-visible.
Cada variante del Button reúne en una cadena las clases de sus estados:
src/components/Button.tsx (extracto)
const VARIANTS = {
primary:
'border-(length:--t101-border-width-100) border-transparent bg-accent-strong-default text-on-accent hover:bg-accent-strong-hover active:bg-accent-strong-active',
secondary:
'border-(length:--t101-border-width-100) border-neutral-strong text-neutral-default hover:bg-neutral-hover active:bg-neutral-active',
};No hay ninguna clase con focus:: el anillo lo pone la utilidad focus-ring, común a todos los controles. Y no hay ninguna clase para default: es lo que se aplica cuando no se cumple ninguna condición.
Active no es current
Las dos palabras parecen sinónimas, y en muchos sistemas se confunden. En DesignToken101 no:
activees "pulsado", siempre. Es un estado de interacción: una variante de Figma y la pseudoclase:activeen CSS. Únicamente lo tienen los controles que hacen una acción. Los enlaces no lo tienen: al pulsarlos se navega y el estado no llega a verse.currentes "el actual": la lección en la que estás, la opción elegida. Es una situación, así que es un prop real en los dos lados, y se anuncia conaria-current.
La lección actual del sidebar se marca con current, no con active, porque active ya tenía un significado en el sistema: es el nombre de los tokens del estado pulsado (background/neutral/active). Es el vocabulario de los estados que viste en Estados en el nombre aplicado a los componentes.
Estados que anuncia ARIA
Algunos estados de situación tienen un atributo ARIA que los anuncia a un lector de pantalla. Una sección que se abre y se cierra lleva aria-expanded; la página actual, aria-current. En código, ese atributo es la fuente del estilo: Tailwind CSS tiene variantes para los atributos ARIA más comunes, y aria-expanded: se aplica cuando el atributo vale true (Tailwind CSS: Hover, focus, and other states).
En Figma, el mismo estado es una variante con otro nombre: las secciones del sidebar de DesignToken101 tienen una propiedad open que en código se traduce en aria-expanded. Lo verás en La accesibilidad del componente.
Un token por estado
No todos los sistemas dan un token a cada estado. El Button de shadcn/ui, una colección de componentes de React con Tailwind CSS, cambia el fondo en hover con una opacidad sobre el mismo token: bg-primary hover:bg-primary/90 (shadcn/ui: button.tsx). Es una forma válida de hacerlo y ahorra tokens.
Recomendación
DesignToken101 usa un token para cada estado (…/hover, …/active). Con una opacidad, el color que se ve depende de lo que hay debajo del botón, así que su contraste no está en tu tabla de pares: cambia con cada fondo. Con un token, el color es fijo en cada modo y su contraste se calcula una vez. Si prefieres la opacidad, comprueba el par con el fondo más desfavorable, como en Fondos con transparencia.
Lo que te llevas
- Un estado de interacción es una variante en Figma y una pseudoclase en código, no un prop.
activesignifica pulsado ycurrentsignifica el actual: el primero lo decide el navegador, el segundo es un prop que se anuncia conaria-current.- Un token por estado tiene un contraste fijo y comprobado; una opacidad depende del fondo que haya debajo.