App Shell
Estructura la base de layout de una pantalla del admin, integrando el menú de navegación, el header, el contenido principal y el panel de chat de Lumi.
- Como estructura raíz de una pantalla del admin: cuando necesita menú lateral de navegación, header fijo y área de contenido principal; es la base de layout sobre la que se monta Page y el resto del contenido de la pantalla.
- Con panel de chat de Lumi: cuando la pantalla necesita mostrar el chat junto al contenido, con la posibilidad de expandirlo a pantalla completa sin perder el contexto de lo que se estaba haciendo.
- Con menú colapsado: cuando el menú lateral debe poder reducirse a un rail angosto (solo íconos) para liberar espacio horizontal, ya sea de forma fija (menuBehavior="inline") o como overlay al pasar el mouse o hacer clic (menuBehavior="popover").
- Estructurar el contenido interno de una pantalla: título, acciones, tabs o secciones. En su lugar, usar Page dentro del children de AppShell.
- Mostrar contenido flotante que no forma parte del layout permanente de la pantalla: como confirmaciones o formularios cortos. En su lugar, usar Side Modal.
- Renderizar más de una instancia en la misma vista: AppShell es la estructura raíz de la aplicación, no un contenedor reutilizable dentro de la pantalla.
Estructura base: menú, header y contenido
Con panel de chat de Lumi
- Menu: slot opcional (menu) que aloja la navegación principal de la aplicación; se expande a menuExpandedWidth o colapsa a un rail de menuCollapsedWidth según menuExpanded.
- Header: franja superior fija (AppShell.Header) con slots leftSlot y rightSlot para acciones globales, como volver, notificaciones o la cuenta del usuario.
- Content: área donde se monta el contenido de la pantalla, normalmente Page; cuando convive con el panel de chat, ambos se agrupan dentro de AppShell.Body.
- Chat (componente AppShell.Chat): panel opcional de Lumi anclado a la derecha del contenido; puede expandirse a pantalla completa con la prop expanded, sin perder de vista el contenido principal.
menuExpanded={true} (default): el menú ocupa menuExpandedWidth (240px por defecto) y muestra la navegación completa, con label junto a cada ícono. Es el estado recomendado para la mayoría de las pantallas en desktop.
menuExpanded={false}: el menú se colapsa a un rail de menuCollapsedWidth (48px por defecto) que muestra solo íconos. Usar cuando la pantalla necesita priorizar el ancho del contenido, por ejemplo con el chat de Lumi abierto o en editores de pantalla completa.
Determina qué pasa con el resto del layout cuando el menú está en menuExpanded={false}.
menuBehavior="inline" (default): el rail ocupa su ancho real dentro del layout; el contenido se reacomoda para ocupar el espacio restante. Usar cuando el colapso del menú debe ser un cambio persistente de layout, con un toggle explícito en el header, como en el ejemplo "Menú plegable".
menuBehavior="popover": el rail se ve igual en reposo, pero al pasar el mouse (menuFlyout={{ trigger: "hover" }}) o hacer clic (menuFlyout={{ trigger: "manual" }}) el menú completo aparece como overlay flotante sin desplazar el contenido, a través de un FloatingPortal que se cierra con Escape o al hacer clic afuera. Usar cuando el menú necesita liberar espacio horizontal de forma permanente (por ejemplo, con el chat de Lumi abierto) sin perder acceso rápido a la navegación completa; ver el ejemplo "Menú plegable con hover" para la interacción completa.
Anclado (default, expanded={false}): el chat ocupa una columna fija junto al contenido (entre 300px y 378px según el breakpoint), sin tapar el resto de la pantalla. Usar como estado inicial al abrir el chat.
Expandido a pantalla completa (expanded={true} o defaultExpanded={true}): el panel pasa a ocupar todo el espacio disponible a la derecha del menú y por debajo del header, con una transición de ancho. Usar cuando el merchant necesita más espacio para leer una respuesta larga de Lumi o interactuar con contenido enriquecido, sin perder el contenido principal, que permanece montado y solo queda oculto detrás. Por tratarse de un panel position: fixed calculado en el cliente, esta variante se demuestra en vivo en el ejemplo "Chat (Lumi)" en vez de en una escena estática.
- FloatingPortal (vía @floating-ui/react) — el overlay de menuBehavior="popover" se renderiza a través de un portal (id="nimbus-popover-floating") para poder superponerse al resto del layout sin quedar recortado por contenedores con overflow: hidden.
AppShell define el layout raíz de toda pantalla del admin en desktop: el menú de navegación permanece visible (expandido o en rail) junto al header fijo y el contenido principal, favoreciendo el trabajo multitarea. Al abrir el chat de Lumi en pantallas medianas, es una buena práctica llevar el menú a menuBehavior="popover" con menuExpanded={false} para liberar el espacio horizontal que el chat necesita, en vez de mantenerlo expandido a ancho completo. Si además convive con un Modal o SideModal que use ignoreAttributeName, marcar el contenido del chat con ese mismo atributo (data-nimbus-outside-press-ignore es el valor por defecto en los componentes de Nimbus) para que un clic dentro del chat no dispare el cierre de ese modal por "clic afuera".
Por debajo del breakpoint md, menuProperties oculta el slot menu ({ display: { xs: "none", md: "block" } } es el valor por defecto). La navegación se resuelve fuera de AppShell, por ejemplo con una barra de navegación fija en la parte inferior de la pantalla, acorde a un uso más acotado y en movimiento en este dispositivo.
Envolver el contenido y el chat dentro de AppShell.Body para que compartan la fila flexible y ambos queden visibles.
Agregar AppShell.Chat como hijo directo de AppShell, sin AppShell.Body: el contenido principal queda sin espacio propio en la grilla.
Combinar menuBehavior="popover" con menuExpanded={false}, para que el rail quede colapsado en el layout y el menú completo solo aparezca como overlay al interactuar.
Dejar menuBehavior="popover" junto con menuExpanded={true}: el menú ya ocupa el ancho completo en el layout y el modo popover nunca llega a activarse.
- Descarte del menú popover: cuando menuBehavior="popover", el overlay se cierra con la tecla Escape o al hacer clic afuera (useDismiss de @floating-ui/react), y puede activarse con foco de teclado además de con el mouse cuando menuFlyout.trigger es "hover".
- Rol del overlay: el menú desplegado en modo popover se renderiza con role="dialog", para que las tecnologías de asistencia lo identifiquen como un panel superpuesto y no como parte del flujo normal del documento.
- Sin landmarks propios: AppShell no aplica roles ARIA de navegación o contenido (nav, main) a sus slots; si la pantalla necesita esa semántica, agregarla en el contenido de menu y children (por ejemplo, a través de Menu, que sí expone esa estructura).
- Contenido del chat siempre montado: al colapsar AppShell.Chat no se desmonta su contenido, por lo que el estado de foco dentro del chat se conserva entre el modo anclado y el expandido a pantalla completa.
Instalá el componente via terminal.
npm install @nimbus-ds/app-shellEstructura mínima con menú lateral, header y contenido.
import React from "react";
import { Box, Button, Icon, Text } from "@nimbus-ds/components";
import { ChevronLeftIcon, GiftBoxIcon, UserIcon } from "@nimbus-ds/icons";
import { AppShell } from "@nimbus-ds/patterns";
const Example: React.FC = () => {
const backButton = (
<Button appearance="transparent">
<Icon source={<ChevronLeftIcon />} />
Volver
</Button>
);
const buttonStack = (
<>
<Button appearance="transparent">
<Icon source={<GiftBoxIcon />} />
Novedades
</Button>
<Button appearance="transparent">
<Icon source={<UserIcon />} />
Mi cuenta
</Button>
</>
);
const sampleMenu = (
<Box
backgroundColor="primary-surface"
borderColor="primary-interactive"
borderStyle="dashed"
borderWidth="1"
borderRadius="2"
width="15rem"
height="100vh"
display="flex"
alignItems="center"
justifyContent="center"
>
<Text fontSize="base" color="primary-interactive">
Menu content
</Text>
</Box>
);
return (
<AppShell menu={sampleMenu}>
<AppShell.Header leftSlot={backButton} rightSlot={buttonStack} />
<Box
backgroundColor="primary-surface"
borderColor="primary-interactive"
borderStyle="dashed"
borderWidth="1"
borderRadius="2"
width="100%"
height="calc(100vh - 66px)"
display="flex"
alignItems="center"
justifyContent="center"
>
<Text fontSize="base" color="primary-interactive">
Children content
</Text>
</Box>
</AppShell>
);
};
export default Example;Las propiedades adicionales se pasan al elemento <AppShell>. Consultá la documentación para ver la lista de atributos aceptados por el elemento <AppShell>.
- Page — Estructura el contenido interno de la pantalla que se monta dentro de AppShell.
- Menu — Navegación lateral que se pasa como valor de la prop menu.
- Side Modal — Panel flotante para contenido que no forma parte del layout permanente; puede anclarse al contenido de AppShell con la prop root.
- Chat Input — Campo de entrada de texto para armar la interfaz de conversación dentro de AppShell.Chat.
AppShell
| Name | Type | Default | Description |
|---|---|---|---|
children* | React.ReactNode | Content for the body of the application. | |
menu | React.ReactNode | Optional slot for left sidebar menu. | |
menuProperties | object | Can be used to control the responsive properties of the AppShell menu so you can change which breakpoint the menu hides under. | |
menuExpanded | boolean | Controls whether the left sidebar (menu) is expanded (true) or collapsed (false). Defaults to true. | |
menuExpandedWidth | string | Sidebar width when expanded. Defaults to "240px". This is a responsive property and you can have the options below available for you to use. '{ "focus": "value", "focusVisible": "value", "focusWithin": "value", "active": "value", "hover": "value", "disabled": "value", "xs": "value", "md": "value", "lg": "value", "xl": "value", "xxl": "value" }' | |
menuCollapsedWidth | string | Sidebar width when collapsed (rail). If provided, the sidebar will render in a compact rail while collapsed. Defaults to "48px". This is a responsive property and you can have the options below available for you to use. '{ "focus": "value", "focusVisible": "value", "focusWithin": "value", "active": "value", "hover": "value", "disabled": "value", "xs": "value", "md": "value", "lg": "value", "xl": "value", "xxl": "value" }' | |
menuBehavior | 'inline' | Determines how the left sidebar behaves when collapsed. - 'inline': current behavior; width changes affect layout. - 'popover': when collapsed, hovering or clicking the rail shows the expanded menu as an overlay without affecting layout. | |
menuFlyout | object | Configuration options for the AppShell flyout (popover) behavior when the menu is collapsed. This consolidates all popover-related props into a single object for simpler usage, while keeping individual top-level props for backward compatibility. | |
contentProperties | object | Consolidated configuration for the content container. |
AppShell.Header
| Name | Type | Default | Description |
|---|---|---|---|
leftSlot | React.ReactNode | Optional content for the left-hand-side slot. | |
rightSlot | React.ReactNode | Optional content for the right-hand-side slot. |
AppShell.Body
| Name | Type | Default | Description |
|---|
AppShell.Chat
| Name | Type | Default | Description |
|---|---|---|---|
defaultExpanded | boolean | Default expanded state for uncontrolled usage. | |
expanded | boolean | Whether the chat panel is expanded to overlay mode, filling the parent container area. The overlay auto-detects the parent bounds (respecting menu and header). |
Ayudanos a mejorar la documentación
¿Encontraste un problema o tenés una sugerencia? Contanos.