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
- A navegação for horizontal — use
mk-navbar - For um menu pontual/dropdown — use
mk-menudiretamente
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
- Abrir: um botão externo (fora da sidebar) define
mobileOpen = true. - Fechar: o gatilho do header vira um ✕ que fecha o overlay; o usuário também pode clicar no backdrop ou pressionar
Escape. Todos disparammkMobileClose— ouça-o e definamobileOpen = falsecom um único handler. - Acima de 767px: o
mobileOpené irrelevante; a sidebar volta a ser um elemento fixo no layoutsidebar | main, e o gatilho do header retoma seu papel de alternarcollapsed(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
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
collapsed | boolean | false | Alterna entre modo rail (só-ícone) e largura total. Propagado reativamente aos descendentes. |
mobileOpen | boolean | false | Controla a visibilidade como overlay abaixo do breakpoint mobile (767px). Enquanto true, collapsed é ignorado. |
locale | string | — | Tag de locale BCP 47 usada para resolver mensagens i18n dos aria-label dos descendentes (ex.: mk-sidebar-header). |
storageKey | string | "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
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
label | string | — | Texto 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.
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
label | string | — | Texto do item. Prioridade sobre o slot default. |
icon | IconName | — | Ícone leading do item. |
badge | number | — | Quando definido, renderiza um mk-badge (standalone) ao lado do rótulo. |
href | string | — | Quando definido, renderiza como <a> em vez de <button>. |
value | string | — | Valor associado, emitido em mkClick/mkNavigate. |
active | boolean | false | Estado selecionado, controlado inteiramente pelo consumidor — sem exclusividade automática entre irmãos. |
disabled | boolean | false | Desabilita 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).
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
label | string | — | Texto do item. Prioridade sobre o slot default. |
badge | number | — | Quando definido, renderiza um mk-badge (standalone) ao lado do rótulo. |
href | string | — | Quando definido, renderiza como <a> em vez de <button>. |
value | string | — | Valor associado, emitido em mkClick/mkNavigate. |
active | boolean | false | Estado selecionado, controlado inteiramente pelo consumidor. |
disabled | boolean | false | Desabilita interação. |
triggerFor | string | — | id 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
| Evento | Componente | Payload | Descrição |
|---|---|---|---|
mkNavigate | mk-sidebar | CustomEvent<{ value: string }> | Agrega os mkClick de qualquer item/sub-item de folha. Ouça apenas este na raiz para tratar o roteamento com um único handler. |
mkCollapseChange | mk-sidebar | CustomEvent<{ collapsed: boolean }> | Emitido ao alternar o modo colapsado, via header ou programaticamente. |
mkMobileOpen | mk-sidebar | CustomEvent<void> | Emitido ao abrir o overlay mobile. |
mkMobileClose | mk-sidebar | CustomEvent<void> | Emitido ao fechar o overlay mobile — Escape, clique no backdrop, ou mobileOpen = false programático. |
mkClick | mk-sidebar-item · mk-sidebar-sub-item | CustomEvent<{ value: string }> | Ativação de um item-folha (sem filhos e sem triggerFor). Borbulha até a raiz como mkNavigate. |
mkToggle | mk-sidebar-item | CustomEvent<{ expanded: boolean }> | Abertura/fechamento da disclosure inline (item com filhos, sidebar expandida). |
Slots
| Componente | Slot | Descrição |
|---|---|---|
mk-sidebar | header | Cabeç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-header | logo | Logotipo 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.
| Tecla | Comportamento |
|---|---|
Tab | Move o foco entre os itens visíveis, na ordem do DOM. Itens desabilitados são pulados. |
Enter / Space | Ativa o item — navega, alterna a disclosure, ou abre o flyout, conforme o caso. |
Escape | Fecha o flyout aberto ou o overlay mobile. |
Segmented
Controle de seleção exclusiva com animação de slide. Composto por `mk-segmented` (contêiner) e `mk-segment` (cada opção).
Speed Dial
Agrupa ações rápidas relacionadas por trás de um único botão flutuante, revelando-as em uma direção configurável ao hover ou clique (`mk-speed-dial` + `mk-speed-dial-action`).