BurgerIcon
Three lines that morph into a close mark when the menu opens. Mobile nav toggles only.
Editorial
<!-- F12c editorial — non-derivable only. Review: Karen. -->
## Ejemplos
Mobile nav toggle (icon only — pair with a control that has a name):
```tsx import { BurgerIcon } from '@/components/atoms/BurgerIcon'; import { IconButton } from '@/components/atoms/IconButton';
<IconButton variant="tertiary" size="m" aria-label={open ? 'Close menu' : 'Open menu'} aria-expanded={open} icon={<BurgerIcon />} onClick={() => setOpen((v) => !v)} /> ```
## Accesibilidad
- `BurgerIcon` is decorative markup (three lines). Put the accessible name on the wrapping button (`aria-label` / `aria-expanded`), never on the icon alone. - Morph-to-close is visual only — keep the label in sync with open/closed state.
## Cuándo no usar
- Not a standalone interactive control — always wrap in `IconButton` (or equivalent button). - Not for desktop primary nav chrome when a labeled text control is clearer.
Uso
import { BurgerIcon } from '@/components/atoms/BurgerIcon';
import { IconButton } from '@/components/atoms/IconButton';
<IconButton aria-label="Open menu" aria-expanded={open}>
<BurgerIcon />
</IconButton>Gotchas
- react
BurgerIcon is presentational only — place it inside IconButton or menu-button for hit target and aria-expanded on the control, not on the icon spans.
- a11y
The three lines are decorative; the parent control must expose the open/closed name (aria-label / aria-expanded).
Anatomía CSS
<div class="burger-icon"> <span class="burger-icon__line"></span> </div>
| Clase | Propósito |
|---|---|
burger-icon | root |
burger-icon__line | element |
Tokens resueltos
Valores finales tras seguir la cadena de tokens. Derivados del source: si un token cambia, esta tabla cambia sola.
| Variante | Prop | Valor | Token |
|---|---|---|---|
| all | bg | currentColor | (literal) |
Animaciones
| Propiedad | Duración | Easing |
|---|---|---|
transform | var(--duration-300) | var(--easing-in-out) |
opacity | var(--duration-200) | var(--easing-in-out) |
CSS mínimo funcional
Autocontenido: sin imports ni tokens. Para previews y prototipos — en producción se consume el CSS del DS.
/* -------------------------------------------------------------------------
Burger Icon
Three-line icon for use inside IconButton.
CSS transition burger ↔ X. GSAP opt-in via [data-menu-button-animate].
States: [data-menu-button="burger"] (default), [data-menu-button="close"]
Parts: .burger-icon, .burger-icon__line
------------------------------------------------------------------------- */
/* ---- Icon container ---- */
.burger-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.1875em;
width: 100%;
height: 100%;
}
/* ---- Lines ---- */
.burger-icon__line {
width: 1.25em;
height: 0.125em;
background-color: currentColor;
border-radius: 9999px;
transform-origin: center;
transition:
transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* ---- CSS-only X state ---- */
[data-menu-button="close"] .burger-icon__line:nth-child(1) {
transform: translateY(0.3125em) rotate(135deg);
}
[data-menu-button="close"] .burger-icon__line:nth-child(2) {
opacity: 0;
transform: scaleX(0);
}
[data-menu-button="close"] .burger-icon__line:nth-child(3) {
transform: translateY(-0.3125em) rotate(-135deg);
}
/* ---- GSAP mode: disable CSS transitions ---- */
[data-menu-button-animate] .burger-icon__line {
transition: none;
}
/* ---- Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
.burger-icon__line {
transition-duration: 0ms;
}
}
Codigo fuente
export function BurgerIcon() { return ( <span className="burger-icon"> <span className="burger-icon__line" data-menu-button-line="" /> <span className="burger-icon__line" data-menu-button-line="" /> <span className="burger-icon__line" data-menu-button-line="" /> </span> ); }