Skip to content

Shell

BlockCSS + JavaScript shell.jsRequires _defaults.js

The shell is the top-level dashboard layout: a full-viewport frame with an icon base rail, an expandable retractable panel of sub-navigation, and a scrollable content area. Layout is driven entirely by data-* attributes; shell.js handles the retractable toggle, header measurement, and persistence.

Application shell
Open ↗
blocks/shell.html
<section class="shell" data-shell>
<div class="shell-body" data-shell-body>
<!-- ============ sidebar ============ -->
<aside class="shell-sidebar" data-shell-sidebar>
<!-- base rail (always visible) -->
<div class="shell-sidebar-base" data-shell-sidebar-base>
<a href="#" class="grid size-10 place-items-center rounded-lg bg-action-primary font-bold text-action-on-primary">
S
</a>
<button type="button" class="shell-sidebar-base-action" data-shell-sidebar-base-action>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
<path d="M21 21l-6 -6" /></svg
></span>
</button>
<hr class="border-muted w-full max-w-13" />
<div class="shell-sidebar-base-scrollable" data-shell-sidebar-base-scrollable>
<a
href="#"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-base-action-id="dashboard"
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v1a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -1" />
<path d="M4 15a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -3" />
<path d="M14 6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -3" />
<path d="M14 17a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v1a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -1" /></svg
></span>
<span data-shell-sidebar-base-action-title>Dashboard</span>
</a>
<a
href="#"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-base-action-id="accounts"
data-active
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" /></svg
></span>
<span data-shell-sidebar-base-action-title>Accounts</span>
</a>
<a
href="#"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-base-action-id="exchange"
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M20 10h-16l5.5 -6" />
<path d="M4 14h16l-5.5 6" /></svg
></span>
<span data-shell-sidebar-base-action-title>Exchange</span>
</a>
<a
href="#"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-base-action-id="transactions"
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 15h-3a1 1 0 0 1 -1 -1v-8a1 1 0 0 1 1 -1h12a1 1 0 0 1 1 1v3" />
<path d="M7 10a1 1 0 0 1 1 -1h12a1 1 0 0 1 1 1v8a1 1 0 0 1 -1 1h-12a1 1 0 0 1 -1 -1l0 -8" />
<path d="M12 14a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /></svg
></span>
<span data-shell-sidebar-base-action-title>Transactions</span>
</a>
<a
href="#"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-base-action-id="reports"
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 3v4a1 1 0 0 0 1 1h4" />
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2" />
<path d="M9 17l0 -5" />
<path d="M12 17l0 -1" />
<path d="M15 17l0 -3" /></svg
></span>
<span data-shell-sidebar-base-action-title>Reports</span>
</a>
</div>
<hr class="border-muted w-full max-w-13" />
<!-- opens / closes the retractable panel; state is persisted -->
<button
type="button"
class="shell-sidebar-base-action"
data-shell-sidebar-base-action
data-shell-sidebar-retractable-toggler
>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 6h16" />
<path d="M7 12h13" />
<path d="M10 18h10" /></svg
></span>
</button>
<a href="#" class="shell-sidebar-base-action" data-shell-sidebar-base-action>
<span data-shell-sidebar-base-action-badge
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065"
/>
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /></svg
></span>
</a>
<button type="button" class="shell-sidebar-base-action" data-shell-sidebar-base-action>
<span data-shell-sidebar-base-action-photo>RA</span>
</button>
</div>
<!-- retractable panel (0-width until [data-shell-sidebar-open]) -->
<div class="shell-sidebar-retractable" data-shell-sidebar-retractable>
<p class="text-xl font-semibold text-foreground xl:text-2xl">Accounts</p>
<a href="#" class="shell-sidebar-retractable-action">Add account</a>
<a href="#" class="shell-sidebar-retractable-action" data-active>Accounts</a>
<a href="#" class="shell-sidebar-retractable-action">Archived accounts</a>
<a href="#" class="shell-sidebar-retractable-action">Receivers & payers</a>
</div>
</aside>
<!-- ============ content ============ -->
<main class="shell-content pb-8" data-shell-content>
<div class="mx-auto w-full max-w-6xl px-6">
<!-- content header: breadcrumb + actions -->
<div class="shell-content-header" data-shell-content-header>
<nav class="shell-breadcrumb" data-shell-breadcrumb>
<a href="#" class="shell-breadcrumb-action" data-shell-breadcrumb-action>Home</a>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 6l6 6l-6 6" />
</svg>
<span class="shell-breadcrumb-current" data-shell-breadcrumb-current>Accounts</span>
</nav>
<div class="shell-content-actions" data-shell-content-actions>
<button type="button" class="button-secondary">Export</button>
<button type="button" class="button-fill-primary"><span>Add account</span></button>
</div>
</div>
<!-- stat cards -->
<div class="mt-2 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div class="rounded-2xl border border-border bg-background-muted p-5">
<p class="text-foreground-subtle">Total balance</p>
<p class="mt-2 text-2xl font-semibold">$128,400</p>
</div>
<div class="rounded-2xl border border-border bg-background-muted p-5">
<p class="text-foreground-subtle">Open accounts</p>
<p class="mt-2 text-2xl font-semibold">312</p>
</div>
<div class="rounded-2xl border border-border bg-background-muted p-5">
<p class="text-foreground-subtle">This month</p>
<p class="mt-2 text-2xl font-semibold text-foreground-positive">+4.6%</p>
</div>
</div>
<!-- a simple list -->
<div class="mt-6 overflow-hidden rounded-2xl border border-border bg-background-muted">
<div class="flex items-center justify-between border-b border-border-muted px-5 py-4">
<p class="font-medium text-foreground">Recent activity</p>
<a href="#" class="text-sm text-foreground-primary">View all</a>
</div>
<ul>
<li class="flex items-center justify-between border-b border-border-muted px-5 py-4 last:border-0">
<span class="text-foreground">Karwan Hassan · deposit</span>
<span class="font-medium text-foreground-positive">+$1,200</span>
</li>
<li class="flex items-center justify-between border-b border-border-muted px-5 py-4 last:border-0">
<span class="text-foreground">Ari Faruq · withdrawal</span>
<span class="font-medium text-foreground-negative">−$540</span>
</li>
<li class="flex items-center justify-between px-5 py-4">
<span class="text-foreground">Zana Rashid · transfer</span>
<span class="font-medium text-foreground">$3,000</span>
</li>
</ul>
</div>
</div>
</main>
</div>
</section>

The shell is three nested regions — a body that lays out a sidebar beside the content. Note the blank lines: each region is a distinct block you can read top-down.

<section class="shell" data-shell>
<div class="shell-body" data-shell-body>
<!-- ① sidebar: an always-visible icon rail + an expandable panel -->
<aside class="shell-sidebar" data-shell-sidebar>
<div class="shell-sidebar-base" data-shell-sidebar-base>
<div class="shell-sidebar-base-scrollable" data-shell-sidebar-base-scrollable>
<a class="shell-sidebar-base-action" data-shell-sidebar-base-action data-active>
<span data-shell-sidebar-base-action-badge><!-- icon --></span>
<span data-shell-sidebar-base-action-title>Accounts</span>
</a>
</div>
<button data-shell-sidebar-base-action data-shell-sidebar-retractable-toggler>
<!-- menu icon -->
</button>
</div>
<div class="shell-sidebar-retractable" data-shell-sidebar-retractable>
<a class="shell-sidebar-retractable-action" data-active>Accounts</a>
</div>
</aside>
<!-- ② content: your scrollable page -->
<main class="shell-content" data-shell-content>
<div class="shell-content-header" data-shell-content-header>
<nav class="shell-breadcrumb" data-shell-breadcrumb></nav>
<div class="shell-content-actions" data-shell-content-actions></div>
</div>
<!-- page content… -->
</main>
</div>
</section>
Attribute On Meaning
data-shell root The shell. Gets data-shell="loaded" [auto-set] once JS is ready (enables transitions).
data-shell-sidebar-open root [auto-set] — present while the retractable panel is open.
data-shell-header element Mobile top bar. Its height is measured into --shell-header-height.
data-shell-body element Row wrapper for sidebar + content.
data-shell-content element Scrollable content column.
Attribute On Meaning
data-shell-sidebar <aside> The whole sidebar (base + retractable).
data-shell-sidebar-base element The always-visible icon rail.
data-shell-sidebar-base-scrollable element Scrollable region of the rail.
data-shell-sidebar-base-action link/button A rail item. Add data-active for the current one.
data-shell-sidebar-base-action-id rail item Identifier for the item (matches a retractable/drawer section).
data-shell-sidebar-base-action-badge child Wrapper for the item’s icon.
data-shell-sidebar-base-action-photo child Wrapper for an avatar (image or initials).
data-shell-sidebar-base-action-title child The item’s label.
data-shell-sidebar-retractable element The expandable sub-nav panel.
data-shell-sidebar-retractable-action link An item in the retractable panel. Add data-active for the current one.
data-shell-sidebar-retractable-toggler button Click target that opens/closes the retractable panel.
  • Retractable toggle — clicking any data-shell-sidebar-retractable-toggler toggles data-shell-sidebar-open on the root and saves it under window._storage.shellSidebar (shell:sidebar).
  • Restore on load — the saved open/closed state is applied on first render.
  • Header height — a ResizeObserver writes the header’s height to the --shell-header-height custom property so content can offset correctly.
  • Transition guard — animations are suppressed until data-shell="loaded" is set, so the initial layout doesn’t animate in.
  • _defaults.js — for window._storage.shellSidebar. Required.
  • Preline — the profile dropdown, tooltips, and the (optional) search modal in a full shell use Preline attributes (data-hs-overlay, hs-tooltip, …). The layout itself works without them.