App Shell

1.9.0

Estrutura a base de layout de uma tela do admin, integrando o menu de navegação, o header, o conteúdo principal e o painel de chat da Lumi.

  • Como estrutura raiz de uma tela do admin: quando é necessário menu lateral de navegação, header fixo e área de conteúdo principal; é a base de layout sobre a qual se monta o Page e o restante do conteúdo da tela.
  • Com painel de chat da Lumi: quando a tela precisa mostrar o chat junto ao conteúdo, com a possibilidade de expandi-lo em tela cheia sem perder o contexto do que estava sendo feito.
  • Com menu recolhido: quando o menu lateral deve poder ser reduzido a um rail estreito (somente ícones) para liberar espaço horizontal, seja de forma fixa (menuBehavior="inline") ou como overlay ao passar o mouse ou clicar (menuBehavior="popover").
  • Estruturar o conteúdo interno de uma tela: título, ações, tabs ou seções. Em vez disso, usar Page dentro do children do AppShell.
  • Mostrar conteúdo flutuante que não faz parte do layout permanente da tela: como confirmações ou formulários curtos. Em vez disso, usar Side Modal.
  • Renderizar mais de uma instância na mesma tela: AppShell é a estrutura raiz da aplicação, não um container reutilizável dentro da tela.

Estrutura base: menu, header e conteúdo

Com painel de chat da Lumi

  • Menu: slot opcional (menu) que abriga a navegação principal da aplicação; expande para menuExpandedWidth ou recolhe para um rail de menuCollapsedWidth conforme menuExpanded.
  • Header: faixa superior fixa (AppShell.Header) com slots leftSlot e rightSlot para ações globais, como voltar, notificações ou a conta do usuário.
  • Content: área onde é montado o conteúdo da tela, normalmente Page; quando convive com o painel de chat, ambos são agrupados dentro de AppShell.Body.
  • Chat (componente AppShell.Chat): painel opcional da Lumi ancorado à direita do conteúdo; pode ser expandido em tela cheia com a prop expanded, sem perder de vista o conteúdo principal.

menuExpanded={true} (default): o menu ocupa menuExpandedWidth (240px por padrão) e mostra a navegação completa, com label junto a cada ícone. É o estado recomendado para a maioria das telas no desktop.

menuExpanded={false}: o menu é recolhido para um rail de menuCollapsedWidth (48px por padrão) que mostra apenas ícones. Usar quando a tela precisa priorizar a largura do conteúdo, por exemplo com o chat da Lumi aberto ou em editores de tela cheia.

Determina o que acontece com o restante do layout quando o menu está em menuExpanded={false}.

menuBehavior="inline" (default): o rail ocupa sua largura real dentro do layout; o conteúdo se reorganiza para ocupar o espaço restante. Usar quando o recolhimento do menu deve ser uma mudança persistente de layout, com um toggle explícito no header, como no exemplo "Menu recolhível".

menuBehavior="popover": o rail parece igual em repouso, mas ao passar o mouse (menuFlyout={{ trigger: "hover" }}) ou clicar (menuFlyout={{ trigger: "manual" }}) o menu completo aparece como overlay flutuante sem deslocar o conteúdo, através de um FloatingPortal que se fecha com Escape ou ao clicar fora. Usar quando o menu precisa liberar espaço horizontal de forma permanente (por exemplo, com o chat da Lumi aberto) sem perder o acesso rápido à navegação completa; ver o exemplo "Menu recolhível com hover" para a interação completa.

Ancorado (default, expanded={false}): o chat ocupa uma coluna fixa junto ao conteúdo (entre 300px e 378px conforme o breakpoint), sem cobrir o restante da tela. Usar como estado inicial ao abrir o chat.

Expandido em tela cheia (expanded={true} ou defaultExpanded={true}): o painel passa a ocupar todo o espaço disponível à direita do menu e abaixo do header, com uma transição de largura. Usar quando o merchant precisa de mais espaço para ler uma resposta longa da Lumi ou interagir com conteúdo enriquecido, sem perder o conteúdo principal, que permanece montado e fica apenas oculto atrás. Por se tratar de um painel position: fixed calculado no cliente, essa variante é demonstrada ao vivo no exemplo "Chat (Lumi)" em vez de em uma cena estática.

  • FloatingPortal (via @floating-ui/react) — o overlay de menuBehavior="popover" é renderizado através de um portal (id="nimbus-popover-floating") para poder se sobrepor ao restante do layout sem ficar recortado por containers com overflow: hidden.

AppShell define o layout raiz de toda tela do admin no desktop: o menu de navegação permanece visível (expandido ou em rail) junto ao header fixo e ao conteúdo principal, favorecendo o trabalho multitarefa. Ao abrir o chat da Lumi em telas médias, é uma boa prática levar o menu para menuBehavior="popover" com menuExpanded={false} para liberar o espaço horizontal que o chat precisa, em vez de mantê-lo expandido em largura total. Se além disso convive com um Modal ou SideModal que use ignoreAttributeName, marcar o conteúdo do chat com esse mesmo atributo (data-nimbus-outside-press-ignore é o valor padrão nos componentes do Nimbus) para que um clique dentro do chat não dispare o fechamento desse modal por "clique fora".

Abaixo do breakpoint md, menuProperties oculta o slot menu ({ display: { xs: "none", md: "block" } } é o valor padrão). A navegação é resolvida fora do AppShell, por exemplo com uma barra de navegação fixa na parte inferior da tela, de acordo com um uso mais reduzido e em movimento nesse dispositivo.

Envolver o conteúdo e o chat dentro de AppShell.Body para que compartilhem a linha flexível e ambos fiquem visíveis.

Adicionar AppShell.Chat como filho direto de AppShell, sem AppShell.Body: o conteúdo principal fica sem espaço próprio na grade.

Combinar menuBehavior="popover" com menuExpanded={false}, para que o rail fique recolhido no layout e o menu completo apareça apenas como overlay ao interagir.

Deixar menuBehavior="popover" junto com menuExpanded={true}: o menu já ocupa a largura total no layout e o modo popover nunca chega a ser ativado.

  • Descarte do menu popover: quando menuBehavior="popover", o overlay se fecha com a tecla Escape ou ao clicar fora (useDismiss do @floating-ui/react), e pode ser ativado com foco de teclado além do mouse quando menuFlyout.trigger é "hover".
  • Papel do overlay: o menu exibido em modo popover é renderizado com role="dialog", para que as tecnologias assistivas o identifiquem como um painel sobreposto e não como parte do fluxo normal do documento.
  • Sem landmarks próprios: AppShell não aplica roles ARIA de navegação ou conteúdo (nav, main) aos seus slots; se a tela precisar dessa semântica, adicioná-la no conteúdo de menu e children (por exemplo, através do Menu, que já expõe essa estrutura).
  • Conteúdo do chat sempre montado: ao recolher o AppShell.Chat, seu conteúdo não é desmontado, portanto o estado de foco dentro do chat é mantido entre o modo ancorado e o expandido em tela cheia.

Instale o componente via terminal.

npm install @nimbus-ds/app-shell

Estrutura mínima com menu lateral, header e conteúdo.

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;

As propriedades adicionais são passadas ao elemento <AppShell>. Consulte a documentação para ver a lista de atributos aceitos pelo elemento <AppShell>.

  • Page — Estrutura o conteúdo interno da tela que é montado dentro do AppShell.
  • Menu — Navegação lateral que é passada como valor da prop menu.
  • Side Modal — Painel flutuante para conteúdo que não faz parte do layout permanente; pode ser ancorado ao conteúdo do AppShell com a prop root.
  • Chat Input — Campo de entrada de texto para montar a interface de conversação dentro do AppShell.Chat.

AppShell

NameTypeDefaultDescription

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'
'popover'

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

NameTypeDefaultDescription

leftSlot

React.ReactNode

Optional content for the left-hand-side slot.

rightSlot

React.ReactNode

Optional content for the right-hand-side slot.

AppShell.Body

NameTypeDefaultDescription

AppShell.Chat

NameTypeDefaultDescription

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).

Ajude-nos a melhorar a documentação

Encontrou um problema ou tem uma sugestão? Conte para a gente.