Skip to content

Components / Sections

Docs Shell

A documentation layout: a sticky sidebar with the current page marked, a reading-progress hairline bound to the scroll, the header and content revealed in two beats, and previous/next links. Content is the default slot.

Live demo

Installation

One command adds the integration, the base tokens and every component.

Then import what you use. Every component is a file; every file states its cost.

The runtime binds now and after every navigation.

Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.

Variants · each row writes the attribute the prop writes; the section's own CSS answers

tone
density

Measured

JavaScript of its own

0 B

Uses Reveal and the shared runtime (1.9 kB raw, once per site). With those included: 3.0 kB raw.

CSS 10.8 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Limited availability

Chrome 115 · not Firefox · Safari 26; needs scroll-timeline. Elsewhere: no progress hairline (Firefox); everything else unchanged.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/docs-shell
src/pages/index.astro
---
import DocsShell from '@/components/moonarc/pro/DocsShell.astro';
---
<DocsShell
  title="Installation"
  description="One command."
  groups={[{ title: 'Start', links: [{ href: '/docs/installation/', label: 'Installation', current: true }, { href: '/docs/runtime/', label: 'Runtime' }] }]}
  next={{ href: '/docs/runtime/', label: 'Runtime' }}
>
  <Content />
</DocsShell>

Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: scroll-progress, reveal.

Props

PropTypeDefaultDescription
level1 | 21Heading level of the headline: 1 on a page's own hero, 2 under another h1 (a demo, or a block further down). At 1 the content column is the page's <main>; at 2 a div, because a page has one main and it is the one around the shell.
groups{ title, links: { href, label, current? }[] }[]noneSidebar groups.
titlestringnonePage title.
descriptionstringnoneLead under the title.
prev{ href, label }nonePrevious page.
next{ href, label }noneNext page.
tone'surface' | 'muted' | 'ink' | 'brand'unset (paints nothing)The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. Each paints --background, --ma-tone-muted (over --muted, with a --border hairline), --ma-tone-ink or --ma-tone-brand (over --primary) with the matching text. With theme.css, a painted tone also re-declares --card, --border, --input and --ring inside the section, so cards and fields follow the ground. Decoration is strongest on brand.
density'compact' | 'cozy' | 'roomy''cozy'Block padding ×0.8 / ×1 / ×1.25 through --ma-density.
labelstring'Docs'Accessible name of the sidebar's nav. Make it unique per page.
pagerLabelstring'Pagination'Accessible name of the previous and next links' nav.
prevLabelstring'Previous'Small text over the previous link.
nextLabelstring'Next'Small text over the next link.

Theming and overrides

The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.

Classes

.ma-docs.ma-docs__content.ma-docs__description.ma-docs__eyebrow.ma-docs__group.ma-docs__group-title.ma-docs__header.ma-docs__main.ma-docs__next.ma-docs__pager.ma-docs__sidebar

Slots

slot="aside"slot="eyebrow"slot="headline"slot="copy"

Reduced motion

Header and content fade in; the progress hairline stays (it is information).

With ClientRouter

Inherits Reveal and ScrollProgress; the sidebar is plain links.

Why it is built this way

Replaces: Starlight-style shells · Docs layouts (Tailwind Plus). See the migration table.

A hairline along the top of the viewport that fills as the page is read.

Chrome 115 · not Firefox · Safari 26scroll

Entrance on scroll that plays once and stays, staggers its children, scrubs with the scroll position when asked, honours reduced motion, and keeps working after every ClientRouter navigation.

every browserscroll

A sticky navigation bar that condenses over the first 120 px of scroll: the row tightens and a hairline appears, bound to the document's scroll timeline.

Chrome 115 · not Firefox · Safari 26scroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown