# Menubar

> La barra de menús de una app: Archivo, Editar, Ver. Un `DropdownMenu` por título, coordinados.

```tsx
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, … } from "sebs7n-ui/menubar"
```

## Ejemplos

### El editor de informes

Tab entra una sola vez a la barra; ← → cambian de título y, con un menú abierto, pasar al de al lado lo abre solo. Los atajos de la derecha son el motivo de que el menubar exista: se abre una vez para descubrirlos.

```tsx
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from "sebs7n-ui/menubar"
import { useState } from "react"

function Editor() {
  const [tema, setTema] = useState("sistema")
  return (
    <Menubar>
      <MenubarMenu>
        <MenubarTrigger>Archivo</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>
            Nuevo informe
            <MenubarShortcut>⌘N</MenubarShortcut>
          </MenubarItem>
          <MenubarItem>
            Abrir…
            <MenubarShortcut>⌘O</MenubarShortcut>
          </MenubarItem>
          <MenubarItem>
            Guardar
            <MenubarShortcut>⌘S</MenubarShortcut>
          </MenubarItem>
          <MenubarSub>
            <MenubarSubTrigger>Exportar</MenubarSubTrigger>
            <MenubarSubContent>
              <MenubarItem>PDF</MenubarItem>
              <MenubarItem>CSV</MenubarItem>
              <MenubarItem>Planilla de cálculo</MenubarItem>
            </MenubarSubContent>
          </MenubarSub>
          <MenubarSeparator />
          <MenubarItem variant="destructive">
            Descartar borrador…
            <MenubarShortcut>⌘⌫</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>

      <MenubarMenu>
        <MenubarTrigger>Editar</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>
            Deshacer
            <MenubarShortcut>⌘Z</MenubarShortcut>
          </MenubarItem>
          <MenubarItem>
            Rehacer
            <MenubarShortcut>⌘⇧Z</MenubarShortcut>
          </MenubarItem>
          <MenubarSeparator />
          <MenubarItem>
            Buscar y reemplazar
            <MenubarShortcut>⌘F</MenubarShortcut>
          </MenubarItem>
        </MenubarContent>
      </MenubarMenu>

      <MenubarMenu>
        <MenubarTrigger>Ver</MenubarTrigger>
        <MenubarContent>
          <MenubarGroup>
            <MenubarLabel>Paneles</MenubarLabel>
            <MenubarCheckboxItem defaultChecked>
              Barra lateral
              <MenubarShortcut>⌘B</MenubarShortcut>
            </MenubarCheckboxItem>
            <MenubarCheckboxItem>Notas al pie</MenubarCheckboxItem>
          </MenubarGroup>
          <MenubarSeparator />
          <MenubarGroup>
            <MenubarLabel>Tema</MenubarLabel>
            <MenubarRadioGroup onValueChange={setTema} value={tema}>
              <MenubarRadioItem value="claro">Claro</MenubarRadioItem>
              <MenubarRadioItem value="oscuro">Oscuro</MenubarRadioItem>
              <MenubarRadioItem value="sistema">Sistema</MenubarRadioItem>
            </MenubarRadioGroup>
          </MenubarGroup>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

### Un título deshabilitado

Cuando un menú entero no aplica al documento abierto, se apaga el título en vez de sacarlo: una barra que cambia de ancho según el archivo obliga a buscar de nuevo cada vez.

```tsx
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarTrigger } from "sebs7n-ui/menubar"

function Deshabilitado() {
  return (
    <Menubar>
      <MenubarMenu>
        <MenubarTrigger>Archivo</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>Nuevo informe</MenubarItem>
          <MenubarItem>Abrir…</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu disabled>
        <MenubarTrigger>Tabla</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>Insertar fila</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
      <MenubarMenu>
        <MenubarTrigger>Ayuda</MenubarTrigger>
        <MenubarContent>
          <MenubarItem>Atajos de teclado</MenubarItem>
          <MenubarItem>Documentación</MenubarItem>
        </MenubarContent>
      </MenubarMenu>
    </Menubar>
  )
}
```

## Props

### Menubar

Hereda las props de `Menubar`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |
| `loopFocus` | `boolean` | — | **Heredada de Base UI.** Si al pasar del último título se vuelve al primero. |
| `modal` | `boolean` | — | **Heredada de Base UI.** Con `true` (el default), mientras hay un menú abierto el resto de la página no recibe clicks. |

### MenubarCheckboxItem

Hereda las props de `Menu.CheckboxItem`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `inset` | `boolean` | — | Corre el texto a la canaleta del tilde (`pl-7`) para que alinee con los `CheckboxItem` y `RadioItem` del mismo menú. En un menú sin tildes no hace falta. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarContent

Hereda las props de `Menu.Popup` y `Menu.Positioner`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `align` | `"center" \| "end" \| "start"` | `"start"` | Cómo se alinea el panel sobre el eje transversal. |
| `alignOffset` | `number \| OffsetFunction` | `0` | Corrimiento en píxeles sobre el eje de alineación. |
| `side` | `"left" \| "right" \| "top" \| "bottom" \| "inline-end" \| "inline-start"` | `"bottom"` | De qué lado del ancla se abre el panel. |
| `sideOffset` | `number \| OffsetFunction` | `6` | Distancia en píxeles entre el ancla y el panel. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarGroup

Hereda las props de `Menu.Group`.

Sin props propias: pasa todo al primitivo.

### MenubarItem

Hereda las props de `Menu.Item`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `external` | `boolean` | — | Lleva a otro sitio: texto en el acento y ↗ al final. |
| `inset` | `boolean` | — | Alinea el texto con el de los ítems que llevan ícono. |
| `variant` | `"default" \| "destructive"` | `"default"` | `destructive`: texto e ícono en rojo, para la acción que borra. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarLabel

Hereda las props de `Menu.GroupLabel`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `inset` | `boolean` | — | Corre el texto a la canaleta del tilde (`pl-7`) para que alinee con los `CheckboxItem` y `RadioItem` del mismo menú. En un menú sin tildes no hace falta. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarMenu

Hereda las props de `Menu.Root`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `actionsRef` | `React.RefObject<MenuRoot.Actions \| null>` | — | **Heredada de Base UI.** Ref con las acciones imperativas de Base UI (`unmount()`), para desmontarlo sin esperar la animación de salida. |
| `defaultOpen` | `boolean` | — | **Heredada de Base UI.** Si arranca abierto. Es la versión no controlada de `open`. |
| `disabled` | `boolean` | — | **Heredada de Base UI.** Apaga la interacción y lo marca con `data-disabled`, que es el atributo del que cuelgan los estilos de apagado. |
| `loopFocus` | `boolean` | — | **Heredada de Base UI.** Si al pasar del último elemento el foco vuelve al primero. |
| `onOpenChange` | `((open: boolean, eventDetails: MenuRoot.ChangeEventDetails) => void)` | — | **Heredada de Base UI.** Se llama con el estado nuevo cada vez que se abre o se cierra. |
| `open` | `boolean` | — | **Heredada de Base UI.** Si está abierto. Pasarla lo vuelve controlado: sin `onOpenChange` ya no se cierra solo. |

### MenubarRadioGroup

Hereda las props de `Menu.RadioGroup`.

Sin props propias: pasa todo al primitivo.

### MenubarRadioItem

Hereda las props de `Menu.RadioItem`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `inset` | `boolean` | — | Corre el texto a la canaleta del tilde (`pl-7`) para que alinee con los `CheckboxItem` y `RadioItem` del mismo menú. En un menú sin tildes no hace falta. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarSeparator

Hereda las props de `Menu.Separator`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarShortcut

Hereda las props de `<span>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarSub

Hereda las props de `Menu.SubmenuRoot`.

Sin props propias: pasa todo al primitivo.

### MenubarSubContent

Hereda las props de `Menu.Popup` y `Menu.Positioner`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `align` | `"center" \| "end" \| "start"` | `"start"` | Cómo se alinea el panel sobre el eje transversal. |
| `alignOffset` | `number \| OffsetFunction` | `-5` | Corrimiento en píxeles sobre el eje de alineación. |
| `side` | `"left" \| "right" \| "top" \| "bottom" \| "inline-end" \| "inline-start"` | `"inline-end"` | De qué lado del ancla se abre el panel. |
| `sideOffset` | `number \| OffsetFunction` | `2` | Distancia en píxeles entre el ancla y el panel. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarSubTrigger

Hereda las props de `Menu.SubmenuTrigger`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `inset` | `boolean` | — | Corre el texto a la canaleta del tilde (`pl-7`) para que alinee con los `CheckboxItem` y `RadioItem` del mismo menú. En un menú sin tildes no hace falta. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### MenubarTrigger

Hereda las props de `Menu.Trigger`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

## Teclado

| Tecla | Qué hace |
|---|---|
| Tab | Entra a la barra y sale. Los títulos son **una sola** parada de tabulación. |
| ← → | Cambia de título. Con un menú abierto, abre el del título al que llegás. |
| Home · End | Primer y último título. |
| Enter · Espacio · ↓ | Abre el menú del título enfocado. |
| ↑ ↓ | Recorre los ítems del menú abierto. |
| → ← | Entra y sale de un submenú. |
| Escribir | Salta al ítem que empieza con esas letras. |
| Enter | Ejecuta y cierra. |
| Escape | Cierra el menú y devuelve el foco a su título. |
| Pasar el mouse | Con un menú abierto, pasar por otro título lo abre sin click. |

## Accesibilidad

- Base UI emite `role="menubar"` con `aria-orientation`, y cada menú es el `role="menu"` del sistema: el lector anuncia «barra de menús, N elementos».
- El recorrido es roving tabindex: la barra entera ocupa una parada de Tab, no una por título.
- Un `MenubarMenu disabled` deja el título en la barra y apagado, en vez de sacarlo: una barra que cambia de ancho según el documento obliga a buscar de nuevo cada vez.
- `MenubarShortcut` es decorativo: el `keydown` lo registra la app. En un check, el atajo va antes del tilde, que ocupa la columna de la derecha.

## Reglas de uso

- **Casi ninguna web necesita un menubar.** Es para apps con decenas de comandos y ninguna otra superficie donde meterlos: un editor, una planilla, una herramienta de diseño.
- **Si los ítems son secciones del sitio, lo que querés es `NavigationMenu`.** Un menubar usado para navegación esconde atrás de tres menús lo que una barra de links mostraba de entrada.
- **Si es un solo grupo de acciones, es un `DropdownMenu` suelto.** Una barra de un título no es una barra.
- Sin fondo ni borde propios: vive dentro del header de la app y hereda su superficie.
- Los atajos son la mitad del trabajo: el menú se abre una vez para descubrir el comando y después se usa el teclado para siempre. Un menubar sin `MenubarShortcut` desperdicia el componente.

## Relacionados

[dropdown-menu](/docs/components/dropdown-menu.md) · [navigation-menu](/docs/components/navigation-menu.md) · [toolbar](/docs/components/toolbar.md) · [context-menu](/docs/components/context-menu.md)
