Design System

Layout

Structural helpers with no visual opinion beyond spacing and optional surfaces. Compose them to build pages; resize your browser to see the responsive behaviour.

Container

Centers content and caps its width with responsive gutters. The outermost wrapper for page content.

import { Container } from "@/design-system";

Max-width variants

maxWidth="sm"
maxWidth="md"
maxWidth="lg"
maxWidth="xl"
maxWidth="full"

Accessibility

  • Purely structural — carries no ARIA role and does not affect semantics.

Stack

Vertical flex layout for stacking related content with a consistent, token-based gap.

import { Stack } from "@/design-system";

Gap scale

gap=2
Item two
Item three
gap=4
Item two
Item three
gap=8
Item two
Item three

Alignment

Centered
Items

Accessibility

  • Renders a plain <div>; add semantic elements or roles as children when needed.

Inline

Horizontal flex layout that wraps by default — toolbars, filter rows, form actions.

import { Inline } from "@/design-system";

Wrapping toolbar

Resize the window to see items wrap onto a new line.

Filter: Status
Filter: Owner
Filter: Date
Clear all

Accessibility

  • Wraps naturally at narrow widths so controls never overflow the viewport.

Grid

Responsive CSS grid with breakpoint-specific column counts, for card and dashboard layouts.

import { Grid } from "@/design-system";

1 → 2 → 4 columns

One column on mobile, two from sm, four from lg.

Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
Card 7
Card 8

Accessibility

  • Purely visual grouping; use a list element around children when order is meaningful.

Cluster

Groups small items — tags, badges, chips — that wrap together with a consistent gap.

import { Cluster } from "@/design-system";

Tag list

DesignEngineeringGrowthResearchShipped

Accessibility

  • Uses flex-wrap; keyboard and screen-reader order follows source order.

Split

Two-region layout that stacks on small screens and splits into a row from lg up.

import { Split } from "@/design-system";

2:1 split

Primary content (grows)
Secondary panel

Accessibility

  • Structural only; each side should contain its own landmark or heading.

Section

Vertical rhythm wrapper for page sections, with an optional title and description slot.

import { Section } from "@/design-system";

With header

Quarterly revenue

Recognised revenue across all regions, updated nightly.

Chart placeholder

Accessibility

  • Renders a semantic <section>; pair with a visible heading for landmark navigation.

Center

Centers content horizontally within an intrinsic max width, with an option to also center vertically.

import { Center } from "@/design-system";

Horizontally centered

Centered narrow column

Accessibility

  • Structural only.

SidebarLayout

Sidebar and main content pairing that stacks below lg and sits side by side from lg up.

import { SidebarLayout } from "@/design-system";

Sidebar on the left, sticky

Overview
Billing
Team
Main content
More content

Accessibility

  • Wrap the sidebar content in a <nav> or <aside> when it carries navigation.

PageLayout

Full page shell with header, sidebar, main and footer slots, filling at least the viewport height.

import { PageLayout } from "@/design-system";

Header, sidebar, main, footer

Header
Page content
Footer

Accessibility

  • Renders exactly one <main>; header/aside/footer are used only when provided.

ScrollArea

Radix ScrollArea with token-styled scrollbars for content that must be capped to a fixed height.

import { ScrollArea } from "@/design-system";

Vertical, max height small

Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12

Horizontal

Col 1
Col 2
Col 3
Col 4
Col 5
Col 6
Col 7
Col 8
Col 9
Col 10

Accessibility

  • Content stays keyboard-scrollable; custom scrollbars are decorative and non-interactive to AT.

ResizablePanelGroup / ResizablePanel / ResizableHandle

Draggable, keyboard-accessible split panels built on react-resizable-panels, for editors and inspector layouts.

import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@/design-system";

Horizontal split

Sidebar
Editor

Accessibility

  • The handle is a focusable element with an accessible name via aria-label.
  • Arrow keys resize the adjacent panels once the handle has focus.

ContentHeader

Lighter header for a section inside a page — same anatomy as PageHeader at a smaller type scale.

import { ContentHeader } from "@/design-system";

When to use

  • Above a table, list, card group or form section inside a page.
  • When a section needs its own local action.

When not to use

  • At the top of a page — that is PageHeader's job.

With a section action

Section title

Supporting copy for this section only.

Section content

Accessibility

  • Renders an <h2> by default; use `as` to keep the heading outline correct when nested deeper.

ActionBar

Toolbar above a view: search and filters lead, secondary/overflow/primary actions trail. Owns no controls of its own.

import { ActionBar } from "@/design-system";

When to use

  • Above a table, list or board that needs search, filters and a primary action.
  • When actions apply to the whole view rather than to a selection.

When not to use

  • For actions on selected rows — use BulkActionBar.
  • For filter chips and clear-all behaviour — use FilterBar.

Search, filters, overflow, primary action

Accessibility

  • Renders role="toolbar" with an accessible name; child controls keep their own semantics.
  • Stacks into rows below lg so nothing is clipped on narrow screens.

SidebarLayout — collapsed & mobile drawer

The same sidebar pairing, narrowed to the icon rail on desktop or moved into a Drawer below lg.

import { SidebarLayout, Sidebar } from "@/design-system";

When to use

  • App shells where navigation must stay reachable but should not consume width.
  • `mobileTrigger` when the sidebar is primary navigation rather than secondary context.

When not to use

  • As a second Sidebar implementation — pass the existing Sidebar into it.

Collapsed rail (desktop)

Main content

Mobile drawer

Below lg the column is hidden and the trigger opens the same sidebar in a Drawer.

Main content

Accessibility

  • Collapsed items surface their label through the existing Tooltip, so the rail is never icon-only to AT.
  • The mobile drawer reuses Drawer's focus trap, Escape handling and labelled title.

DashboardGrid / DashboardGridItem

Layout-only tile grid with responsive reflow and variable spans. Carries no dashboard content of its own.

import { DashboardGrid, DashboardGridItem } from "@/design-system";

When to use

  • Any tile-based overview where tiles differ in importance and width.
  • When one tile should span the full row and others sit beside each other.

When not to use

  • For arbitrary content grids with equal cells — plain Grid is enough.
  • As a dashboard: it is a primitive, not a screen.

4 columns with variable spans

span="full"
span=2
span=1
span=1

Accessibility

  • Reading order follows DOM order; spans change width, never sequence.
  • Reflows to a single column on mobile so no tile is horizontally scrollable.

DetailLayout

Primary content with a secondary information column, for record, profile, settings and object-detail views.

import { DetailLayout } from "@/design-system";

When to use

  • Record pages where metadata, related items or activity supports the main content.
  • When the secondary column should follow the content on mobile.

When not to use

  • For navigation beside content — use SidebarLayout.
  • For two equally important panels — use SplitPanel.

Content + supporting details

Primary content

The main record body.

Content

Accessibility

  • Primary content is always first in the DOM; the aside stacks below it on mobile without reordering meaning.
  • The secondary column renders an <aside> with an accessible name.

SplitPanel

Two content panels side by side at a fixed ratio, stacking below lg.

import { SplitPanel } from "@/design-system";

When to use

  • Comparison views, editor + preview, form + summary.
  • When both panels are equally important.

When not to use

  • When the user should drag the divider — use ResizablePanelGroup.
  • For a content/metadata relationship — use DetailLayout.

2:1 with a divider

Primary panel
Secondary panel

Accessibility

  • Each panel renders a <section>; pass primaryLabel/secondaryLabel to name them.
  • Stacks in DOM order on mobile — neither panel is hidden.

SettingsLayout

Settings navigation beside the active settings panel. Adds no navigation of its own.

import { SettingsLayout } from "@/design-system";

When to use

  • Multi-section settings, preferences and account areas.
  • Whenever sections are navigated rather than scrolled.

When not to use

  • For a single settings form — FormPageLayout is enough.

Navigation + panel

Section settings

Generic placeholder panel for the selected section.

Settings content

Accessibility

  • Renders a labelled <nav>; the items come from the existing Sidebar or Tabs components.
  • Navigation precedes the panel in the DOM, so it stacks above it on mobile.

FormPageLayout

Page shell for a single form: header, form sections, action footer — with an optional guidance aside.

import { FormPageLayout } from "@/design-system";

When to use

  • Create/edit pages and multi-section forms.
  • When the commit action belongs at the end of the page rather than inline.

When not to use

  • For a short form inside a dialog or card — compose FormField directly.
  • It arranges only: fields come from FormSection/FormField, actions from Button.

Header → sections → footer

Section

Page title

One or two lines of supporting description that explain what this page contains.

ActiveUpdated 2 minutes ago

Section one

Grouped, related fields.

Section two

Draft — not yet submitted

Accessibility

  • Renders a single <form>; the header title stays the page <h1>.
  • Form column is capped to a readable measure; the aside stacks below the fields on mobile.

TablePageLayout

Page shell for a collection view: header, toolbar, table, pagination — with one slot for empty/no-results/error/loading states.

import { TablePageLayout } from "@/design-system";

When to use

  • Any list or table page that needs search, filters and paging.
  • When empty and error states should occupy the same region as the table.

When not to use

  • It recreates nothing: pass the existing DataTable, FilterBar, Pagination and state components.

Populated collection view

Section

Page title

One or two lines of supporting description that explain what this page contains.

ActiveUpdated 2 minutes ago
Generic placeholder records
Status
Record oneActive
Record twoDraft
Record threeActive
Record fourArchived

Showing 1–4 of 4 rows

4 records

Empty state in the same slot

Section

Page title

One or two lines of supporting description that explain what this page contains.

ActiveUpdated 2 minutes ago

No records yet

Generic placeholder empty state, reused from the states layer.

Accessibility

  • The `state` slot replaces the table region, so assistive tech is never shown an empty grid.
  • DataTable keeps its caption, sortable headers and selection semantics.

MasterDetailLayout

Master list beside a detail panel on desktop; a list → detail navigation flow below lg.

import { MasterDetailLayout } from "@/design-system";

When to use

  • Inboxes, queues and browse-then-inspect workflows.
  • When users move between records without losing their place in the list.

When not to use

  • When a record deserves its own page — use DetailLayout.
  • For navigation rather than records — use SidebarLayout.

Two panes (desktop) / list → detail (mobile)

Select a record, then narrow the window to see the mobile navigation pattern.