Skip to main content

AppShell

Info:Shell html svelte astro Success: coverage 21/21

The three-row application scaffold: toolbar over a left/main/right body over a status bar.

Live demo

live · @xoji/astro

AppShell

A full three-row scaffold — Toolbar · Dock + main · Statusbar

Tab into the frame to reveal the skip link in the top-left corner.

Skip to main content
xoji
Success:Live

Theme preview

The main region scrolls independently between the fixed chrome.

Background

#0b0d12

Foreground

#e6e9ef

Accent

#6ea8fe

xoji-default OKLCH 276 tokens 100% coverage

AppShell is the outermost layout frame for a full-screen application. It establishes a three-row grid (a top toolbar, a flexible body, and a bottom status bar) where the body is itself a three-column grid of a left rail, a scrollable main column, and a right rail.

Every region is an optional named slot, so the same scaffold collapses cleanly from a full IDE-style layout down to a bare main column. The main region is a real <main> landmark that owns the only scroll, keeping the chrome pinned. An optional skip link, hidden until focused, lets keyboard users jump straight past the chrome to the content. It carries no chrome of its own: the Astro and HTML bindings emit the same light-DOM structure, and the custom element is a transparent display: contents host that contributes nothing to the layout.

When to use

How this component composes with the rest of the set.

Fill the toolbar slot with Toolbar and the statusbar slot with Statusbar for the matching chrome.
Use Panel in the left / right slots for collapsible rails.
Mount one AppShell per application; nest layout components inside the main slot rather than nesting shells.

Props

1 prop, straight from the manifest.

PropTypeDefaultBindingsDescription
skipLink string | boolean
html svelte astro
Renders a skip link targeting the main region. `true` uses the default label; a string overrides it. The Astro binding also accepts a `skip-link` slot for richer content.

Appearance

States

main-focus

.xoji-main:focus-visible

The main region after the skip link moves focus to it; an inset ring marks the landing.

skip-link-focus

.xoji-app__skip-link:focus-visible

The skip link revealed on keyboard focus, sliding into view with the standard ring.

Anatomy

The named parts that make up the component, with their selectors.

app

.xoji-app

The outer three-row grid filling the viewport, carrying the body background and base typography.

--body-bg --fg-0 --font-sans --text-body --leading-normal

body

.xoji-app__body

The middle row split into the left rail, the main column, and the right rail.

main

.xoji-main

The scrollable <main> landmark and skip-link target; takes the remaining space.

--space-5

skip-link

.xoji-app__skip-link

The keyboard-only jump link, off-screen until focused, sliding into the top-left when it is.

--font-sans --text-sm --weight-medium --leading-tight --accent --accent-fg --border-thin --radius-md --space-2 --space-3 --space-4 --duration-fast --ease-standard

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 21/21 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --accent-fg --body-bg --border-normal --border-thick --border-thin --duration-fast --ease-standard --fg-0 --font-sans --leading-normal --leading-tight --radius-md --ring --space-2 --space-3 --space-4 --space-5 --text-body --text-sm --weight-medium

Slots

default
html svelte astro

The main content, rendered inside the scrollable <main> landmark.

toolbar
html svelte astro

The top row; typically a Toolbar with the app title and global actions.

left
html svelte astro

The left rail; typically navigation.

right
html svelte astro

The right rail; typically contextual detail.

statusbar
html svelte astro

The bottom row; typically a Statusbar.

skip-link
astro

Custom content for the skip link (Astro only); falls back to a default label otherwise.

Accessibility

The main content is a native <main> landmark, so assistive tech can jump to it directly.
The optional skip link is the first focusable element and targets #main (which carries tabindex="-1"), letting keyboard users bypass the chrome.
The skip link is positioned off-screen and only slides into view on :focus-visible, so it stays out of the visual layout until needed.
<main> receives a focus ring when the skip link moves focus to it, confirming the landing point.
The custom element host is display: contents, so it adds no box and never disturbs the landmark or grid structure.

Code

Full application scaffold

Toolbar, left and right rails, scrollable main, a status bar, and a skip link.

<xoji-app-shell skip-link>
	<header slot="toolbar" class="xoji-toolbar">App title and global actions</header>
	<nav slot="left" class="xoji-panel">Primary navigation</nav>

	<h1>Page content</h1>
	<p>Everything in the default slot lands in the scrollable main column.</p>

	<aside slot="right" class="xoji-panel">Contextual details</aside>
	<footer slot="statusbar" class="xoji-statusbar">Ready</footer>
</xoji-app-shell>
<script lang="ts">
	import { AppShell } from "@xoji/svelte";
</script>

<AppShell skipLink>
	{#snippet toolbar()}
		<header class="xoji-toolbar">App title and global actions</header>
	{/snippet}
	{#snippet left()}
		<nav class="xoji-panel">Primary navigation</nav>
	{/snippet}

	<h1>Page content</h1>
	<p>Everything in the default slot lands in the scrollable main column.</p>

	{#snippet right()}
		<aside class="xoji-panel">Contextual details</aside>
	{/snippet}
	{#snippet statusbar()}
		<footer class="xoji-statusbar">Ready</footer>
	{/snippet}
</AppShell>
---
import { AppShell } from "@xoji/astro";
---

<AppShell skipLink>
	<header slot="toolbar" class="xoji-toolbar">App title and global actions</header>
	<nav slot="left" class="xoji-panel">Primary navigation</nav>

	<h1>Page content</h1>
	<p>Everything in the default slot lands in the scrollable main column.</p>

	<aside slot="right" class="xoji-panel">Contextual details</aside>
	<footer slot="statusbar" class="xoji-statusbar">Ready</footer>
</AppShell>