@redrob-labs/ui v1.0.2 · Redrob Group Design System 2026

AppShell

Frames · src/components/AppShell/AppShell.tsx

The product frame: sidebar, the work, an optional rail.

The lockup goes through Mark rather than a bare img, so it follows the theme. A bare img here is how the first screen lost its wordmark in dark.

product is validated against the seven real products and dropped otherwise. The component knows only the attribute; the colours are the product-<p>-wash tokens. An unrecognised name would set an attribute that matches no token and silently render no wash, so it is rejected instead.

main holds the page heading, not just the body, so the skip link lands on the one h1 rather than above it. tabIndex={-1} is what lets focus actually arrive.

The folded state is remembered per browser when uncontrolled, and every localStorage call is wrapped because a private window throws.

Import

import { AppShell } from '@redrob-labs/ui';

Rendered

The design system's own preview case, run against this package's build. The parity gate compares this rendering to the reference bundle's.

Props

PropTypeNotes
product string Product name, e.g. Desk. Sets the product wash at the top of the sidebar.
mark string
markDark string
symbol string The symbol alone, shown when the sidebar is folded.
nav AppShellNavItem[]
navLabel string
aside React.ReactNode Extra content at the bottom of the sidebar.
theme React.ReactNode
title React.ReactNode
meta React.ReactNode A line under the title: what this screen is showing.
actions React.ReactNode
foot React.ReactNode
rail React.ReactNode A right-hand panel about the current run.
railLabel string
measure boolean false lets the work area run full width instead of holding a reading measure.
collapsible boolean
collapsed boolean
defaultCollapsed boolean
collapseLabel string
expandLabel string
skipLabel React.ReactNode
className string
children React.ReactNode
onCollapsedChange (collapsed: boolean) => void

Exported types

AppShellNavItem