Navigation

Burger

Botón de menú hamburguesa

Preview

size
active

Code

import css from "./Burger.module.css";

type Size = "sm" | "md" | "lg";

interface ResponsiveSize {
  base: Size;
  mobile?: Size;
  tablet?: Size;
  desktop?: Size;
  wide?: Size;
}

interface BurgerProps {
  size: Size | ResponsiveSize;
  "aria-label": string;
  "aria-controls"?: string;
  active?: boolean;
  onClick: () => void;
}

function getSizeClasses(size: Size | ResponsiveSize): string {
  if (typeof size === "string") {
    return css[size];
  }

  const classes = [css[`${size.base}_base`]];

  if (size.mobile) classes.push(css[`${size.mobile}_mobile`]);
  if (size.tablet) classes.push(css[`${size.tablet}_tablet`]);
  if (size.desktop) classes.push(css[`${size.desktop}_desktop`]);
  if (size.wide) classes.push(css[`${size.wide}_wide`]);

  return classes.join(" ");
}

export default function Burger({
  size,
  "aria-label": ariaLabel,
  "aria-controls": ariaControls,
  active,
  onClick,
}: BurgerProps) {
  return (
    <button
      type="button"
      className={`
        ${css.burger}
        ${active ? css.active : ""}
        ${getSizeClasses(size)}
      `}
      onClick={onClick}
      aria-label={ariaLabel}
      aria-expanded={active ?? false}
      aria-controls={ariaControls}
    >
      <span></span>
      <span></span>
      <span></span>
    </button>
  );
}

Props

PropTypeRequiredDescription
size"sm" | "md" | "lg" | ResponsiveSizerequiredTamaño del botón (caja y trazos). Fijo o responsive.
aria-labelstringrequiredNombre accesible del botón (icon-only: sin él, sería anónimo para un lector de pantalla).
aria-controlsstring—Id del panel que el botón abre y cierra; sin él, nada dice qué controla.
activeboolean—Estado abierto (muta a X, aria-expanded).
onClick() => voidrequiredCallback al hacer clic; el padre posee el estado abierto.