Makuco UI
ComponentesNavigation

Sidebar

Navegação lateral persistente e composta, com modo rail (só-ícone) e overlay mobile. (`mk-sidebar`)

O mk-sidebar é uma composição de componentes para navegação lateral persistente — painéis administrativos, dashboards e qualquer aplicação com múltiplas seções/sub-seções acessíveis a partir de um menu fixo à esquerda. Alterna entre largura total e um modo rail (só-ícone), e vira um overlay abaixo do breakpoint mobile.

Diferente da maioria dos componentes, ele não é uma única tag: você monta a navegação combinando mk-sidebar-header, mk-sidebar-title, mk-sidebar-item, mk-sidebar-sub-item e mk-divider. Por isso vale conhecer bem a estrutura antes de usá-lo.

mk-sidebar não navega sozinho — o consumidor escuta mkNavigate na raiz (ou mkClick em cada item) e decide o roteamento, marcando o item ativo com active.

Quando usar

Use quando:
  • A aplicação tiver uma árvore de seções fixa lateral (não pontual como um dropdown)
  • For necessário economizar espaço horizontal via um modo rail só-ícone
  • Houver até 3 níveis de profundidade de navegação
Prefira uma alternativa quando:
  • A navegação for horizontal — use mk-navbar
  • For um menu pontual/dropdown — use mk-menu diretamente

Estrutura

A sidebar é montada por composição. A árvore abaixo mostra como as tags se encaixam — o mk-sidebar-header vai no slot header, e todo o resto (títulos, itens, divisores) no slot padrão, em qualquer ordem:

mk-sidebar                              ← raiz; dona de collapsed / mobileOpen
├── mk-sidebar-header        [slot="header"]
│   └── (logo)               [slot="logo"] ← mk-illustration-icon + nome da marca

├── mk-sidebar-title         "Administrador"      ← rótulo de grupo
├── mk-sidebar-item          "Dashboard"          ← nível 1 (com ícone)
├── mk-sidebar-item          "Financeiro"         ← nível 1 (com filhos)
│   ├── mk-sidebar-sub-item  "Faturas"            ← nível 2
│   └── mk-sidebar-sub-item  "Relatórios"         ← nível 2, trigger-for="reports-menu"
│       └── mk-menu#reports-menu                  ← nível 3 (flyout, tag externa)
│           ├── mk-menu-item "Overview"
│           ├── mk-menu-item "Features"
│           └── mk-menu-item "Changelog"

├── mk-divider                                    ← separador entre grupos
├── mk-sidebar-title         "Configurações"
├── mk-sidebar-item          "Perfil"
└── mk-sidebar-item          "Notificações"       ← nível 1 (com badge)

Só existem 2 níveis de indentação

A árvore visual da sidebar é limitada a dois níveis: mk-sidebar-item (nível 1) e mk-sidebar-sub-item (nível 2, sempre filho direto de um mk-sidebar-item).

Para um 3º nível, não aninhe mais componentes de sidebar. Use um mk-menu externo e aponte um mk-sidebar-sub-item para ele com a prop trigger-for (o id do menu). O 3º nível abre como um flyout, reaproveitando toda a infraestrutura de posicionamento e teclado do mk-menu.

Exemplo completo

Uma sidebar aproveitando todos os recursos: logo (um mk-illustration-icon) com o nome da marca no header, títulos de seção, itens de nível 1 com ícones e badge, sub-itens de nível 2 aninhados, e um sub-item que abre um mk-menu de nível 3 via trigger-for.

import {
  MkDivider,
  MkIllustrationIcon,
  MkMenu,
  MkMenuItem,
  MkSidebar,
  MkSidebarHeader,
  MkSidebarItem,
  MkSidebarSubItem,
  MkSidebarTitle,
} from '@db1/makuco-ui-react';

<MkSidebar onMkNavigate={(e) => router.push(e.detail.value)}>
  <MkSidebarHeader slot="header">
    <div slot="logo" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <MkIllustrationIcon icon="rocket" color="brand" size="sm" />
      <span>Makuco</span>
    </div>
  </MkSidebarHeader>

  <MkSidebarTitle label="Administrador" />
  <MkSidebarItem label="Dashboard" icon="layout-dashboard" value="dashboard" active />
  <MkSidebarItem label="Financeiro" icon="wallet">
    <MkSidebarSubItem label="Faturas" value="invoices" />
    <MkSidebarSubItem label="Relatórios" triggerFor="reports-menu" />
  </MkSidebarItem>
  <MkSidebarItem label="Notificações" icon="bell" badge={3} value="notifications" />

  <MkDivider />

  <MkSidebarTitle label="Configurações" />
  <MkSidebarItem label="Perfil" icon="user" value="profile" />
  <MkSidebarItem label="Segurança" icon="shield" value="security" />

  {/* 3º nível: mk-menu externo referenciado por trigger-for */}
  <MkMenu id="reports-menu" size="sm" placement="right">
    <MkMenuItem value="overview" label="Overview" icon="eye" />
    <MkMenuItem value="features" label="Features" icon="star" />
    <MkMenuItem value="changelog" label="Changelog" icon="history" />
  </MkMenu>
</MkSidebar>
<mk-sidebar (mkNavigate)="router.navigate([$event.detail.value])">
  <mk-sidebar-header slot="header">
    <div slot="logo" style="display: flex; align-items: center; gap: 8px">
      <mk-illustration-icon icon="rocket" color="brand" size="sm"></mk-illustration-icon>
      <span>Makuco</span>
    </div>
  </mk-sidebar-header>

  <mk-sidebar-title label="Administrador"></mk-sidebar-title>
  <mk-sidebar-item label="Dashboard" icon="layout-dashboard" value="dashboard" active></mk-sidebar-item>
  <mk-sidebar-item label="Financeiro" icon="wallet">
    <mk-sidebar-sub-item label="Faturas" value="invoices"></mk-sidebar-sub-item>
    <mk-sidebar-sub-item label="Relatórios" trigger-for="reports-menu"></mk-sidebar-sub-item>
  </mk-sidebar-item>
  <mk-sidebar-item label="Notificações" icon="bell" [badge]="3" value="notifications"></mk-sidebar-item>

  <mk-divider></mk-divider>

  <mk-sidebar-title label="Configurações"></mk-sidebar-title>
  <mk-sidebar-item label="Perfil" icon="user" value="profile"></mk-sidebar-item>
  <mk-sidebar-item label="Segurança" icon="shield" value="security"></mk-sidebar-item>

  <!-- 3º nível: mk-menu externo referenciado por trigger-for -->
  <mk-menu id="reports-menu" size="sm" placement="right">
    <mk-menu-item value="overview" label="Overview" icon="eye"></mk-menu-item>
    <mk-menu-item value="features" label="Features" icon="star"></mk-menu-item>
    <mk-menu-item value="changelog" label="Changelog" icon="history"></mk-menu-item>
  </mk-menu>
</mk-sidebar>

Modo colapsado (rail)

Defina collapsed para reduzir a sidebar a um rail só-ícone. Todos os mk-sidebar-item/mk-sidebar-title descendentes resolvem esse estado automaticamente — não é necessário propagá-lo manualmente item a item. Um mk-sidebar-item com filhos, ao ser clicado no modo rail, expande a sidebar e abre a disclosure inline.

O estado colapsado é persistido

A sidebar grava collapsed em localStorage sob a chave da prop storage-key ("mk-sb-state" por padrão) e o restaura na montagem — a preferência do usuário sobrevive a recarregamentos, sem que você precise gerenciá-la.

Se você já controla collapsed a partir do seu próprio estado (ou não quer persistência), passe storage-key="" para desativá-la. Em SSR a persistência é silenciosamente ignorada.

<MkSidebar collapsed>
  <MkSidebarHeader slot="header">
    <MkIllustrationIcon slot="logo" icon="rocket" color="brand" size="sm" />
  </MkSidebarHeader>
  <MkSidebarItem label="Dashboard" icon="layout-dashboard" value="dashboard" active />
  <MkSidebarItem label="Financeiro" icon="wallet">
    <MkSidebarSubItem label="Faturas" value="invoices" />
  </MkSidebarItem>
</MkSidebar>
<mk-sidebar collapsed>
  <mk-sidebar-header slot="header">
    <mk-illustration-icon slot="logo" icon="rocket" color="brand" size="sm"></mk-illustration-icon>
  </mk-sidebar-header>
  <mk-sidebar-item label="Dashboard" icon="layout-dashboard" value="dashboard" active></mk-sidebar-item>
  <mk-sidebar-item label="Financeiro" icon="wallet">
    <mk-sidebar-sub-item label="Faturas" value="invoices"></mk-sidebar-sub-item>
  </mk-sidebar-item>
</mk-sidebar>

Overlay mobile

Abaixo de 767px (mesmo breakpoint do mk-navbar), a sidebar deixa de ficar fixa no fluxo e passa a se comportar como um overlay: defina mobileOpen para exibi-la com backdrop e slide-in a partir da esquerda. Enquanto mobileOpen é true, collapsed é ignorado, o scroll do body é bloqueado e o foco é movido para a navegação — restaurado ao elemento anterior quando fecha.

A sidebar não tem gatilho de abertura próprio

No mobile, a sidebar não renderiza um botão para abri-la — o gatilho de colapso do mk-sidebar-header controla apenas o modo rail (collapsed), não o overlay. Cabe ao consumidor fornecer o botão de abertura (tipicamente um hambúrguer na mk-navbar ou app bar) que define mobileOpen = true.

O fechamento, ao contrário, já vem embutido: o próprio gatilho do mk-sidebar-header vira um botão de fechar (ícone ✕) enquanto o overlay está aberto, além de clique no backdrop, tecla Escape e o evento mkMobileClose — basta zerar seu estado no handler.

Como funciona

  1. Abrir: um botão externo (fora da sidebar) define mobileOpen = true.
  2. Fechar: o gatilho do header vira um ✕ que fecha o overlay; o usuário também pode clicar no backdrop ou pressionar Escape. Todos disparam mkMobileClose — ouça-o e defina mobileOpen = false com um único handler.
  3. Acima de 767px: o mobileOpen é irrelevante; a sidebar volta a ser um elemento fixo no layout sidebar | main, e o gatilho do header retoma seu papel de alternar collapsed (modo rail).

O overlay só assume o posicionamento fixo abaixo de 767px. Para ver o slide-in no preview abaixo, reduza a largura da janela ou use o modo dispositivo do navegador (DevTools).

import { MkIconButton, MkSidebar } from '@db1/makuco-ui-react';

const [mobileOpen, setMobileOpen] = useState(false);

return (
  <>
    {/* Gatilho de abertura — vive na app bar/navbar, FORA da sidebar */}
    <MkIconButton
      icon="menu"
      label="Abrir navegação"
      onMkClick={() => setMobileOpen(true)}
    />

    <MkSidebar
      mobileOpen={mobileOpen}
      onMkMobileClose={() => setMobileOpen(false)}
    >
      {/* ...header, títulos e itens... */}
    </MkSidebar>
  </>
);
<!-- Gatilho de abertura — na app bar/navbar, FORA da sidebar -->
<mk-icon-button
  icon="menu"
  label="Abrir navegação"
  (mkClick)="mobileOpen = true"
></mk-icon-button>

<mk-sidebar [mobileOpen]="mobileOpen" (mkMobileClose)="mobileOpen = false">
  <!-- ...header, títulos e itens... -->
</mk-sidebar>

Terceiro nível via trigger-for

O 3º nível de navegação é sempre um mk-menu externo, referenciado via trigger-for em um mk-sidebar-sub-item — nunca um componente de sidebar aninhado mais fundo. Isso mantém a árvore visual em 2 níveis e reaproveita a mesma infraestrutura de posicionamento/teclado do mk-menu, sem lógica duplicada.

import { MkMenu, MkMenuItem, MkSidebar, MkSidebarItem, MkSidebarSubItem } from '@db1/makuco-ui-react';

<MkSidebar>
  <MkSidebarItem label="Financeiro" icon="wallet">
    <MkSidebarSubItem label="Faturas" value="invoices" />
    <MkSidebarSubItem label="Relatórios" triggerFor="reports-submenu" />
  </MkSidebarItem>

  <MkMenu id="reports-submenu" size="sm" placement="right">
    <MkMenuItem value="overview" label="Overview" icon="eye" />
    <MkMenuItem value="features" label="Features" icon="star" />
    <MkMenuItem value="changelog" label="Changelog" icon="history" />
  </MkMenu>
</MkSidebar>
<mk-sidebar>
  <mk-sidebar-item label="Financeiro" icon="wallet">
    <mk-sidebar-sub-item label="Faturas" value="invoices"></mk-sidebar-sub-item>
    <mk-sidebar-sub-item label="Relatórios" trigger-for="reports-submenu"></mk-sidebar-sub-item>
  </mk-sidebar-item>

  <mk-menu id="reports-submenu" size="sm" placement="right">
    <mk-menu-item value="overview" label="Overview" icon="eye"></mk-menu-item>
    <mk-menu-item value="features" label="Features" icon="star"></mk-menu-item>
    <mk-menu-item value="changelog" label="Changelog" icon="history"></mk-menu-item>
  </mk-menu>
</mk-sidebar>

Props — mk-sidebar

PropTipoPadrãoDescrição
collapsedbooleanfalseAlterna entre modo rail (só-ícone) e largura total. Propagado reativamente aos descendentes.
mobileOpenbooleanfalseControla a visibilidade como overlay abaixo do breakpoint mobile (767px). Enquanto true, collapsed é ignorado.
localestringTag de locale BCP 47 usada para resolver mensagens i18n dos aria-label dos descendentes (ex.: mk-sidebar-header).
storageKeystring"mk-sb-state"Chave de localStorage sob a qual collapsed é persistido e restaurado na montagem. Passe "" para desativar a persistência. Ignorado em SSR.

Props — mk-sidebar-header

Não possui props. Todo o comportamento deriva da mk-sidebar ancestral: o ícone e o aria-label do gatilho seguem collapsed/mobileOpen (chevron para colapsar, ✕ para fechar o overlay), e o clique alterna esse estado na raiz. O conteúdo visual entra pelo slot logo.

Props — mk-sidebar-title

PropTipoPadrãoDescrição
labelstringTexto do rótulo de seção. Tem prioridade sobre o slot default. Oculto no modo rail.

Props — mk-sidebar-item

Item de navegação de nível 1. Pode conter mk-sidebar-sub-item aninhados como filhos diretos.

PropTipoPadrãoDescrição
labelstringTexto do item. Prioridade sobre o slot default.
iconIconNameÍcone leading do item.
badgenumberQuando definido, renderiza um mk-badge (standalone) ao lado do rótulo.
hrefstringQuando definido, renderiza como <a> em vez de <button>.
valuestringValor associado, emitido em mkClick/mkNavigate.
activebooleanfalseEstado selecionado, controlado inteiramente pelo consumidor — sem exclusividade automática entre irmãos.
disabledbooleanfalseDesabilita interação.

Props — mk-sidebar-sub-item

Item de navegação de nível 2. Sempre filho direto de um mk-sidebar-item. Não possui icon (subitens não têm ícone leading).

PropTipoPadrãoDescrição
labelstringTexto do item. Prioridade sobre o slot default.
badgenumberQuando definido, renderiza um mk-badge (standalone) ao lado do rótulo.
hrefstringQuando definido, renderiza como <a> em vez de <button>.
valuestringValor associado, emitido em mkClick/mkNavigate.
activebooleanfalseEstado selecionado, controlado inteiramente pelo consumidor.
disabledbooleanfalseDesabilita interação.
triggerForstringid de um mk-menu externo. Abre um 3º nível de navegação como flyout. Substitui a emissão de mkClick — o item passa a abrir o menu em vez de navegar.

Eventos

EventoComponentePayloadDescrição
mkNavigatemk-sidebarCustomEvent&lt;&#123; value: string &#125;&gt;Agrega os mkClick de qualquer item/sub-item de folha. Ouça apenas este na raiz para tratar o roteamento com um único handler.
mkCollapseChangemk-sidebarCustomEvent&lt;&#123; collapsed: boolean &#125;&gt;Emitido ao alternar o modo colapsado, via header ou programaticamente.
mkMobileOpenmk-sidebarCustomEvent&lt;void&gt;Emitido ao abrir o overlay mobile.
mkMobileClosemk-sidebarCustomEvent&lt;void&gt;Emitido ao fechar o overlay mobile — Escape, clique no backdrop, ou mobileOpen = false programático.
mkClickmk-sidebar-item · mk-sidebar-sub-itemCustomEvent&lt;&#123; value: string &#125;&gt;Ativação de um item-folha (sem filhos e sem triggerFor). Borbulha até a raiz como mkNavigate.
mkTogglemk-sidebar-itemCustomEvent&lt;&#123; expanded: boolean &#125;&gt;Abertura/fechamento da disclosure inline (item com filhos, sidebar expandida).

Slots

ComponenteSlotDescrição
mk-sidebarheaderCabeçalho da sidebar. Use mk-sidebar-header.
mk-sidebar(padrão)Conteúdo da sidebar, em qualquer ordem/quantidade: mk-sidebar-title, mk-sidebar-item, mk-divider.
mk-sidebar-headerlogoLogotipo ou identidade visual da aplicação — um mk-illustration-icon, um <img>, ou logo + nome da marca. Opcional — oculto quando vazio.
mk-sidebar-title(padrão)Texto do rótulo, usado quando label não é fornecido.
mk-sidebar-item(padrão)mk-sidebar-sub-item aninhados (quando há filhos) ou o texto do label (fallback).
mk-sidebar-sub-item(padrão)Texto do label, usado quando label não é fornecido.

Acessibilidade

mk-sidebar renderiza um <nav role="navigation" aria-label="Navegação principal">. Enquanto mobileOpen é true, a navegação recebe aria-modal="true", o scroll do body é bloqueado e o foco é movido para ela — restaurado ao elemento anterior quando fecha.

Cada mk-sidebar-item/mk-sidebar-sub-item reflete seu estado via aria-disabled, aria-current="page" (quando active em um item-folha), aria-expanded (disclosure inline ou flyout de 3º nível) e aria-haspopup="menu" (em sub-itens com triggerFor). Quando a sidebar está colapsada, o rótulo visível é ocultado mas preservado via aria-label no próprio item.

No flyout de 3º nível (o mk-menu externo via triggerFor), a navegação por teclado — setas ↑/↓, Home/End, typeahead e Escape — é totalmente delegada ao mk-menu, já que seu conteúdo são mk-menu-item nativos.

TeclaComportamento
TabMove o foco entre os itens visíveis, na ordem do DOM. Itens desabilitados são pulados.
Enter / SpaceAtiva o item — navega, alterna a disclosure, ou abre o flyout, conforme o caso.
EscapeFecha o flyout aberto ou o overlay mobile.

On this page