{
  "$schema": "https://mian.ro/schema/v2/registry.json",
  "schemaVersion": "2.0.0",
  "generatedAt": "2026-10-02T13:14:06.957Z",
  "id": "app-shell",
  "name": "App shell",
  "category": "Sections",
  "description": "The frame of a web app: a sidebar, a top bar and a content area that becomes a drawer layout on small screens.",
  "tags": [
    "app shell",
    "dashboard layout",
    "admin layout",
    "sidebar layout",
    "application",
    "saas app",
    "backoffice",
    "console"
  ],
  "requiresJs": false,
  "license": "LicenseRef-MIAN-1.0",
  "composition": {
    "role": "frame",
    "intents": [
      "admin dashboard layout",
      "web app frame",
      "sidebar and top bar",
      "saas app",
      "back office",
      "crm layout"
    ],
    "prominence": "low",
    "density": "high",
    "worksAfter": [],
    "worksBefore": [],
    "alternatives": [
      "docs-layout"
    ],
    "avoid": "Marketing sections (hero, bento) inside an app, apps are built from stats, tables, forms and charts."
  },
  "url": "https://mian.ro/components/app-shell",
  "markdownUrl": "https://mian.ro/ai/components/app-shell.md",
  "classes": [
    {
      "name": "mn-shell",
      "description": "The frame (usually the whole page)."
    },
    {
      "name": "mn-shell-side",
      "description": "The sidebar (holds an mn-sidebar). Shown when the shell is at least 60rem wide."
    },
    {
      "name": "mn-shell-body · mn-shell-top · mn-shell-main",
      "description": "Content column, sticky top bar, and main area."
    },
    {
      "name": "mn-shell-menu",
      "description": "The top-bar button that opens the navigation drawer; hidden when the sidebar shows."
    },
    {
      "name": "mn-shell-head",
      "description": "Page title, description and actions at the top of the main area."
    }
  ],
  "accessibility": [
    "Use <aside> or <nav aria-label> for the sidebar, <header> for the top bar and <main> for content.",
    "The drawer on small screens is a <dialog class=\"mn-drawer\"> opened with data-mn-open, so focus is trapped and Escape closes it.",
    "Mark the current page with aria-current=\"page\" in the sidebar."
  ],
  "examples": [
    {
      "title": "App shell",
      "description": null,
      "html": "<div class=\"mn-shell\" style=\"min-height:26rem;border:1px solid var(--mn-border);border-radius:var(--mn-radius-box);overflow:hidden\">\n  <aside class=\"mn-shell-side\" style=\"height:auto\" aria-label=\"Workspace\"><a class=\"mn-header-brand\" href=\"#\"><svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" fill=\"currentColor\"><path d=\"M4 16c3-8 6 4 9-4s5 2 7-2\" stroke=\"currentColor\" stroke-width=\"2.6\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>Pace</a>\n    <nav class=\"mn-sidebar\" aria-label=\"App\"><div class=\"mn-sidebar-group\"><a class=\"mn-sidebar-link\" href=\"#\" aria-current=\"page\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 20V10M10 20V4M16 20v-7M22 20H2\"/></svg> Overview</a><a class=\"mn-sidebar-link\" href=\"#\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M9 6h11M9 12h11M9 18h11M4 6h.01M4 12h.01M4 18h.01\"/></svg> Activities</a><a class=\"mn-sidebar-link\" href=\"#\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z\"/></svg> Settings</a></div></nav>\n  </aside>\n  <div class=\"mn-shell-body\">\n    <header class=\"mn-shell-top\"><button class=\"mn-btn mn-btn-ghost mn-btn-icon mn-shell-menu\" aria-label=\"Open navigation\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 7h16M4 12h16M4 17h16\"/></svg></button><div class=\"mn-input-group\" style=\"max-width:18rem;flex:1\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m20 20-3.5-3.5\"/></svg><input class=\"mn-input\" placeholder=\"Search activities\" aria-label=\"Search activities\"></div><span class=\"mn-avatar mn-avatar-sm\" style=\"margin-inline-start:auto\">AP</span></header>\n    <main class=\"mn-shell-main\"><div class=\"mn-shell-head\"><div><h1>This week</h1><p>42.8 km over 5 runs</p></div><button class=\"mn-btn mn-btn-sm\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 5v14M5 12h14\"/></svg> Log a run</button></div>\n      <div class=\"mn-stats\"><div class=\"mn-stat\"><div class=\"mn-stat-label\">Distance</div><div class=\"mn-stat-value\">42.8 km</div></div><div class=\"mn-stat\"><div class=\"mn-stat-label\">Avg pace</div><div class=\"mn-stat-value\">5:12</div></div></div></main>\n  </div>\n</div>"
    }
  ],
  "css": ".mn-shell { container: mn-shell / inline-size; display: flex; min-height: 100dvh; background: var(--mn-bg); }\n.mn-shell-side {\n  display: none; flex: 0 0 15.5rem; flex-direction: column; gap: 1.25rem; position: sticky; top: 0; align-self: flex-start;\n  height: 100dvh; overflow: auto; padding: 1rem .75rem; border-inline-end: var(--mn-border-w) solid var(--mn-border); background: var(--mn-surface);\n}\n.mn-shell-side .mn-sidebar { flex: 1; }\n.mn-shell-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.mn-shell-top {\n  position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: .75rem; min-height: 3.6rem;\n  padding: .5rem clamp(1rem, 3cqi, 2rem); border-bottom: var(--mn-border-w) solid var(--mn-border);\n  background: color-mix(in srgb, var(--mn-bg) 88%, transparent); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);\n}\n.mn-shell-main { container: mn / inline-size; display: grid; gap: 1.5rem; align-content: start; padding: clamp(1rem, 3cqi, 2rem); }\n.mn-shell-main > * { min-width: 0; }\n.mn-shell-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1rem; }\n.mn-shell-head > div { display: grid; gap: .3rem; }\n.mn-shell-head h1 { margin: 0; font: var(--mn-heading-weight) 1.6rem/1.2 var(--mn-font-heading); letter-spacing: -.02em; }\n.mn-shell-head p { margin: 0; color: var(--mn-muted); font-size: .9375rem; }\n@container mn-shell (min-width: 60rem) {\n  .mn-shell-side { display: flex; }\n  .mn-shell-menu { display: none; }",
  "js": null,
  "install": {
    "css": "https://mian.ro/dist/mian.css",
    "js": null,
    "registryItem": "https://mian.ro/r/app-shell.json"
  }
}
