Sidebar <mv-sidebar>
应用侧边栏:带工具提示的动画图标栏,状态持久化,分组,可折叠的嵌套分区,计数器,工作区切换器和用户菜单,容器较窄时为滑出面板(dialog),Ctrl/⌘ + B 快捷键。
暂停 播放
分类 区块 类型 Web Component(<mv-sidebar>) 状态 稳定版 同时安装 dialog , tooltip Keywords sidebar, navigation, app-shell, drawer, rail, collapsible, layout
When to use
An app needs side navigation that collapses to an icon rail and remembers its state Navigation has groups, nested sections, counters, a workspace switcher and a user menu On narrow containers the navigation should slide out as a panel with a keyboard shortcut
Avoid when
A whole dashboard layout with header, KPIs and search is needed → use App Shell instead The site is a public marketing site better served by a top bar → use Navbar instead
安装
node scripts/add.mjs sidebar --out ./src/marvelous
使用 Marvelous UI MCP 服务器的 AI 智能体:install_components({ slugs: ["sidebar"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。
复制的文件(含依赖):tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, components/dialog/dialog.js, components/dialog/dialog.css, core/position.js, components/tooltip/tooltip.js, components/tooltip/tooltip.css, core/observe.js, components/sidebar/sidebar.js, components/sidebar/sidebar.css。
用法
标准标记,可在此基础上通过属性、data-* 和 CSS 变量进行定制:
<div class="mv-sidebar-layout" data-variant="inset" id="sb-demo" style="height:640px;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);overflow:hidden">
<mv-sidebar label="Main navigation" storage-key="mv-demo-sidebar">
<div class="mv-sidebar-header">
<mv-menu placement="bottom-start">
<button class="mv-sidebar-item" data-size="lg" type="button">
<span class="mv-sidebar-logo" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19V5l8 7 8-7v14"/></svg></span>
<span class="mv-sidebar-label"><strong>Nova Studio</strong><small>Pro plan · 12 members</small></span>
<mv-icon class="mv-sidebar-item-end" name="chevrons-up-down"></mv-icon>
</button>
<div data-content style="--mv-menu-width:15rem">
<div class="mv-menu-label">Workspaces</div>
<div role="group" data-name="workspace">
<button role="menuitemradio" aria-checked="true" value="nova">Nova Studio <span class="mv-menu-shortcut">⌘1</span></button>
<button role="menuitemradio" value="lumen">Lumen Labs <span class="mv-menu-shortcut">⌘2</span></button>
<button role="menuitemradio" value="opal">Opal Coffee <span class="mv-menu-shortcut">⌘3</span></button>
</div>
<hr>
<button role="menuitem" value="new-workspace"><mv-icon name="plus"></mv-icon>New workspace</button>
</div>
</mv-menu>
</div>
<nav class="mv-sidebar-content" aria-label="Sections">
<div class="mv-sidebar-group">
<h2 class="mv-sidebar-group-label">Platform</h2>
<ul class="mv-sidebar-menu">
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="dashboard"></mv-icon><span class="mv-sidebar-label">Dashboard</span></a></li>
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="inbox"></mv-icon><span class="mv-sidebar-label">Inbox</span><span class="mv-sidebar-badge" data-variant="accent">4<span class="mv-sr-only"> unread</span></span></a></li>
<li class="mv-sidebar-sub">
<button class="mv-sidebar-item"><mv-icon name="folder"></mv-icon><span class="mv-sidebar-label">Projects</span><span class="mv-sidebar-badge">12</span></button>
<ul class="mv-sidebar-submenu">
<li><a class="mv-sidebar-subitem" href="#sb-demo" aria-current="page">Customer portal redesign</a></li>
<li><a class="mv-sidebar-subitem" href="#sb-demo">Mobile app</a></li>
<li><a class="mv-sidebar-subitem" href="#sb-demo">Opal rebrand</a></li>
<li><a class="mv-sidebar-subitem" href="#sb-demo">Archived</a></li>
</ul>
</li>
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="calendar"></mv-icon><span class="mv-sidebar-label">Calendar</span><span class="mv-sidebar-badge" data-variant="danger">2<span class="mv-sr-only"> conflicts</span></span></a></li>
<li class="mv-sidebar-sub">
<button class="mv-sidebar-item"><mv-icon name="chart"></mv-icon><span class="mv-sidebar-label">Reports</span></button>
<ul class="mv-sidebar-submenu">
<li><a class="mv-sidebar-subitem" href="#sb-demo">Sales</a></li>
<li><a class="mv-sidebar-subitem" href="#sb-demo">Traffic</a></li>
<li><a class="mv-sidebar-subitem" href="#sb-demo">Retention</a></li>
</ul>
</li>
</ul>
</div>
<div class="mv-sidebar-group">
<h2 class="mv-sidebar-group-label">Team</h2>
<ul class="mv-sidebar-menu">
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="users"></mv-icon><span class="mv-sidebar-label">Members</span></a></li>
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="file"></mv-icon><span class="mv-sidebar-label">Documents</span></a></li>
</ul>
</div>
<div class="mv-sidebar-group" data-push>
<ul class="mv-sidebar-menu">
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="help"></mv-icon><span class="mv-sidebar-label">Help & support</span></a></li>
<li><a class="mv-sidebar-item" href="#sb-demo"><mv-icon name="settings"></mv-icon><span class="mv-sidebar-label">Settings</span></a></li>
</ul>
</div>
</nav>
<div class="mv-sidebar-footer">
<mv-menu placement="top-start">
<button class="mv-sidebar-item" data-size="lg" type="button">
<span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:200" aria-hidden="true"><span class="mv-avatar-fallback">MP</span></span>
<span class="mv-sidebar-label"><strong>Maya Patel</strong><small>[email protected] </small></span>
<mv-icon class="mv-sidebar-item-end" name="chevrons-up-down"></mv-icon>
</button>
<div data-content style="--mv-menu-width:15rem">
<div class="mv-menu-label">My account</div>
<button role="menuitem" value="profile"><mv-icon name="user"></mv-icon>Profile <span class="mv-menu-shortcut">⇧⌘P</span></button>
<button role="menuitem" value="billing"><mv-icon name="credit-card"></mv-icon>Billing</button>
<button role="menuitem" value="notifications"><mv-icon name="bell"></mv-icon>Notifications</button>
<hr>
<button role="menuitem" value="sign-out"><mv-icon name="log-out"></mv-icon>Log out</button>
</div>
</mv-menu>
</div>
</mv-sidebar>
<main class="mv-sidebar-inset" aria-label="Content">
<style>@container mv-sidebar-inset (width < 34rem) { #sb-demo .sb-demo-hint { display: none } }</style>
<header style="display:flex;align-items:center;gap:.5rem;height:3.5rem;padding:0 1rem;border-bottom:1px solid var(--mv-border);flex-shrink:0">
<button class="mv-button" data-variant="ghost" data-size="icon" data-mv-sidebar-toggle aria-label="Show or hide the sidebar" title="Sidebar (Ctrl B)">
<mv-icon name="sidebar"></mv-icon>
</button>
<div class="mv-separator" role="separator" aria-orientation="vertical" data-orientation="vertical" style="height:1rem;min-height:1rem;align-self:center"></div>
<nav class="mv-breadcrumb" aria-label="Breadcrumb" data-size="sm" style="min-width:0">
<ol>
<li><a href="#sb-demo">Projects</a></li>
<li><span aria-current="page" class="mv-breadcrumb-truncate">Customer portal redesign</span></li>
</ol>
</nav>
<span style="margin-inline-start:auto;font-size:.75rem;color:var(--mv-fg-muted);white-space:nowrap" class="sb-demo-hint">Collapse: <kbd class="mv-kbd-group"><kbd class="mv-kbd" data-size="sm">Ctrl</kbd><kbd class="mv-kbd" data-size="sm">B</kbd></kbd></span>
</header>
<div style="display:grid;gap:1rem;padding:1.25rem;align-content:start">
<div>
<h1 style="margin:0;font-size:1.25rem;font-weight:600;letter-spacing:-.01em">Customer portal redesign</h1>
<p style="margin:.25rem 0 0;color:var(--mv-fg-muted);font-size:.875rem">Launching Oct 14 · 18 of 24 tasks done</p>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:.75rem">
<article class="mv-card" data-size="sm">
<div class="mv-card-content" style="display:grid;gap:.5rem">
<span style="font-size:.8125rem;color:var(--mv-fg-muted)">Progress</span>
<strong style="font-size:1.5rem;font-weight:600">75%</strong>
<progress class="mv-progress" data-size="sm" max="100" value="75" aria-label="Project progress"></progress>
</div>
</article>
<article class="mv-card" data-size="sm">
<div class="mv-card-content" style="display:grid;gap:.5rem">
<span style="font-size:.8125rem;color:var(--mv-fg-muted)">Budget used</span>
<strong style="font-size:1.5rem;font-weight:600">$31,400</strong>
<progress class="mv-progress" data-size="sm" data-color="warning" max="100" value="84" aria-label="Budget used"></progress>
</div>
</article>
<article class="mv-card" data-size="sm">
<div class="mv-card-content" style="display:grid;gap:.5rem">
<span style="font-size:.8125rem;color:var(--mv-fg-muted)">Reviews to schedule</span>
<strong style="font-size:1.5rem;font-weight:600">2</strong>
<span style="font-size:.75rem;color:var(--mv-fg-muted)">Product design · Accessibility</span>
</div>
</article>
</div>
<div style="min-height:14rem;border:1px dashed var(--mv-border-strong);border-radius:var(--mv-radius-lg);display:grid;place-items:center;color:var(--mv-fg-subtle);font-size:.8125rem;text-align:center;padding:1rem">Page content: the sidebar collapses to an icon rail and becomes a slide-out panel below 768px.</div>
</div>
</main>
</div>
API
Attributes
Name 类型 Default Description collapsedboolean Collapsed state (reflected, persisted when storage-key is set). collapsibleicon | offcanvas | none iconicon: icon rail; offcanvas: hides completely; none: fixed. storage-keystring localStorage key used to remember the state between visits. labelstring SidebarAccessible name of the region and the mobile panel. breakpointnumber (px) 768Width of the .mv-sidebar-layout container below which the sidebar becomes a slide-out panel. hotkeystring bKey combined with Ctrl/⌘ to toggle; empty to disable. Ignored while typing in a field or when another modal dialog is open. data-stateexpanded | collapsed Set automatically (also data-sidebar on the layout). data-mobileboolean Set automatically in panel mode.
Properties
Name 类型 Description stringsPartial<Record<string, string>> Overrides for the default text: expand, collapse (edge rail tooltip), close (mobile panel Close button). English defaults. Can be set before the element is defined.
Methods
Name Description toggle()Collapses/expands; in mobile mode, opens/closes the panel. collapse() / expand()Forces the state.
Events
Name Description mv-toggledetail: { collapsed }.
Content structure
Name Description .mv-sidebar-header / -content / -footerRegions; -content scrolls (use a <nav aria-label>). .mv-sidebar-group > .mv-sidebar-group-label + ul.mv-sidebar-menuTitled group (the list is named by its title). data-push on a group pushes it to the bottom. a/button.mv-sidebar-itemItem: icon (<mv-icon name> or an inline <svg>) + .mv-sidebar-label (+ .mv-sidebar-badge). aria-current="page" for the current page. data-size="lg" for a switcher (logo/avatar + <strong>/<small>). li.mv-sidebar-subCollapsible section: button.mv-sidebar-item + ul.mv-sidebar-submenu of a.mv-sidebar-subitem; data-open to open it (automatic when it contains the current page). [data-mv-sidebar-toggle]Trigger button (inside the same .mv-sidebar-layout, or value = sidebar selector). aria-expanded, aria-controls and aria-keyshortcuts handled (an aria-keyshortcuts you set is kept).
CSS classes
Name Description mv-sidebar-layoutFlex container for sidebar + content; data-variant="inset": content as a floating card. mv-sidebar-insetContent area (container query named mv-sidebar-inset). mv-sidebar-logo / -badge / -item-end / -separatorLogo tile, counter (data-variant="accent | danger | warning | success"; the collapsed rail's dot takes the same tone), trailing icon (<mv-icon> or <svg>), divider. mv-sidebar-hide-collapsedHides an element in rail mode.
CSS variables
Name Default Description --mv-sidebar-width16remExpanded width. --mv-sidebar-width-icon3remRail width. --mv-sidebar-bgvar(--mv-bg-subtle)Background. --mv-sidebar-highlightHover background.
Accessibility
Named region; lists named by their group title; aria-current="page"; collapsible sections as <button aria-expanded aria-controls> (reported collapsed while the icon rail hides them). In rail mode, labels stay in the DOM (accessible names intact) and a tooltip appears on hover and keyboard focus; Escape dismisses it. Trigger with aria-expanded and aria-keyshortcuts. Mobile mode: modal dialog (focus trap, Escape, inert background, focus returned to the trigger) with a Close button. Ctrl/⌘ + B, never taken from a text field. Forced colors: focus, current page and counters drawn with system colors.