Tucano v0.37.2

Menú lateral

La lista de navegación, y nada más: es la parte que se repite igual en todo proyecto. No hay componente ni JavaScript propio — son clases sobre enlaces. Qué va en ella, cómo se agrupa y dónde vive sigue siendo decisión tuya: fija en el lateral en escritorio, dentro de un panel lateral en el móvil, o en ambos.

Haz clic en los elementos

El elemento actual lleva color, fondo y peso en el primer nivel, y una píldora neutra dentro del submenú. Los grupos abren y cierran con la animación del acordeón.

En el móvil, dentro de un panel lateral

La misma lista en un panel lateral desde la izquierda — el patrón de menú de aplicación en pantalla pequeña.

Ejemplos

Las piezas del menú, una a una.

Elementos y elemento actual

is-active marca la página en la que está la persona.

Icono y contador

__icon a la izquierda; __count es la .tuc-badge is-plain, empujada a la derecha.

Secciones y separador

__section es la etiqueta de un bloque; __separator, una línea entre bloques.

Submenú

Un <details> con __sub; la flecha apunta a la derecha cerrado y hacia abajo abierto.

Cómo usar

Un <nav> con la clase y enlaces dentro. El data-tuc-accordion en el <nav> solo hace falta cuando hay submenú: es lo que anima los <details>.

<nav class="tuc-menu" aria-label="Principal" data-tuc-accordion>

  <!-- elemento simple -->
  <a class="tuc-menu__item" href="/billing/">
    <span class="tuc-menu__icon"><svg>…</svg></span>Facturación
  </a>

  <!-- elemento con contador -->
  <a class="tuc-menu__item" href="/products/">
    <span class="tuc-menu__icon"><svg>…</svg></span>Productos
    <span class="tuc-badge is-plain tuc-menu__count">12</span>
  </a>

  <!-- elemento con submenú -->
  <details open>
    <summary class="tuc-menu__item">
      <span class="tuc-menu__icon"><svg>…</svg></span>Rendimiento
    </summary>
    <div class="tuc-menu__sub">
      <a class="tuc-menu__item is-active" href="/performance/period/" aria-current="page">Por período</a>
      <a class="tuc-menu__item" href="/performance/branches/">Sucursales</a>
    </div>
  </details>

  <hr class="tuc-menu__separator">
  <div class="tuc-menu__section">Registros</div>
  <a class="tuc-menu__item" href="/customers/">Clientes</a>
</nav>

En la plantilla de Django

El elemento actual sale de la ruta resuelta. Escribe el menú una vez en un include y marca la página correcta en todas:

{% with route=request.resolver_match.url_name %}
<nav class="tuc-menu" aria-label="Principal" data-tuc-accordion>
  <a class="tuc-menu__item{% if route == 'contract-list' %} is-active{% endif %}"
     href="{% url 'contract-list' %}"{% if route == 'contract-list' %} aria-current="page"{% endif %}>
    Contratos
  </a>

  <details{% if route|slice:":12" == 'performance-' %} open{% endif %}>
    <summary class="tuc-menu__item">Rendimiento</summary>
    <div class="tuc-menu__sub">
      <a class="tuc-menu__item{% if route == 'performance-period' %} is-active{% endif %}"
         href="{% url 'performance-period' %}">Por período</a>
    </div>
  </details>
</nav>
{% endwith %}

Deja abierto en la plantilla el grupo que contiene la página actual: quien llega por un enlace de submenú ya ve dónde está.

En el lateral y en el panel lateral

El menú no sabe dónde vive. En escritorio, ponlo en una columna fija; en el móvil, el mismo include va dentro de un panel lateral desde la izquierda:

<dialog class="tuc-drawer is-left is-sm" id="menu-main" aria-labelledby="menu-main-title">
  <div class="tuc-drawer__panel">
    <div class="tuc-drawer__top">
      <div class="tuc-drawer__header">
        <h2 class="tuc-drawer__title" id="menu-main-title">Panel</h2>
      </div>
      <button type="button" class="tuc-btn is-ghost is-icon is-sm tuc-drawer__close" aria-label="Cerrar" data-tuc-drawer-close>…</button>
    </div>
    <div class="tuc-drawer__body">
      {% include "partials/menu.html" %}
    </div>
  </div>
</dialog>

<button class="tuc-btn is-outline is-icon" aria-label="Abrir menú" data-tuc-drawer="#menu-main">…</button>

En la columna fija del escritorio, conviértela en una columna flex con altura, con la marca arriba y el menú debajo. El .tuc-menu ocupa el espacio que queda y se desplaza solo cuando la lista pasa de la pantalla — la marca se queda fija arriba. En el panel lateral, quien se desplaza es su cuerpo, y no hace falta nada.

<aside style="display: flex; flex-direction: column; height: 100vh; position: sticky; top: 0">
  <a href="/">Mi marca</a>
  <nav class="tuc-menu" aria-label="Panel">…</nav>
</aside>

El elemento que abre y revela hijos es un <details>, y la apertura reutiliza el acordeón: la animación, el teclado y el funcionamiento sin JavaScript ya vienen listos. El menú se ocupa solo de la lectura — quién es hijo de quién, y dónde está el actual dentro del árbol.

El <summary> lleva tuc-menu__item y queda con el mismo aspecto que sus vecinos, con la etiqueta alineada a la izquierda y la flecha empujada a la derecha. Los hijos van en tuc-menu__sub, sangrados y sujetos a un riel a la izquierda. El hijo no repite icono: hereda el contexto del padre, y el punto delante marca la fila sin disputar atención con la fila de iconos de arriba.

La flecha gira 90 grados, no 180

Derecha cuando está cerrado, hacia abajo cuando está abierto — así se lee un árbol de navegación: "hay algo aquí dentro" frente a "esta es la rama abierta". Y el riel a la izquierda existe porque la sangría sola se pierde en cuanto la lista pasa de cuatro o cinco filas.

El elemento actual lleva tres pistas

En el primer nivel, color de acento, fondo y peso — ninguna depende solo del color. Dentro del submenú el actual es una píldora neutra con el punto encendido: el color de acento queda para el nivel de arriba, y dos elementos naranjas en la misma columna dirían menos.

Teclado y accesibilidad

Son enlaces y <details>, y el teclado es el suyo: nada que aprender, nada que implementar.

TeclaAcción
Tab Shift+TabRecorre los elementos, incluidos los títulos de submenú; los hijos de un grupo cerrado quedan fuera del recorrido
EnterSigue el enlace, o abre y cierra el submenú enfocado
EspacioAbre y cierra el submenú enfocado

Escribe aria-current="page" junto a is-active: la clase dibuja, el atributo es lo que el lector de pantalla anuncia. Dale al <nav> un aria-label cuando haya más de una navegación en la página. Y no uses role="menu" aquí: ese rol promete las flechas de un menú de aplicación, y esta lista es navegación común.

Clases

Solo clases — el menú no tiene JavaScript ni opciones. Lo que anima el submenú es el acordeón.

Clase o atributoDóndePara qué
tuc-menu<nav>La lista, en columna
tuc-menu__item<a> o <summary>Una fila del menú, con la altura de un control
is-active.tuc-menu__itemEl elemento actual: resaltado en el primer nivel, píldora neutra en el submenú
tuc-menu__icon<span> en el elementoCaja de 16px para el icono, en el color secundario; en el elemento activo, en el color de acento
tuc-menu__count.tuc-badge is-plain en el elementoEmpuja el contador a la derecha, con dígitos de ancho fijo
tuc-menu__separator<hr>Línea entre bloques
tuc-menu__section<div>Etiqueta de un bloque, en mayúsculas
tuc-menu__sub<div> dentro del <details>Los hijos del submenú, sangrados y con riel
data-tuc-accordion<nav>Anima la apertura de los submenús; data-single="true" deja uno abierto a la vez