01 — Getting started
Quick start
Install via CDN
Load the framework from the canonical host
downstage.it
without copying files into your project. Use the same filenames as a local install, with an absolute origin.
The snippets use https:// so they work on HTTPS pages without mixed-content blocking.
<link rel="stylesheet" href="https://downstage.it/downstage.css"> <script src="https://downstage.it/downstage.js" defer></script>
Pre-load the icon sprite and reference symbols with the same path prefix:
<object data="https://downstage.it/downstage-icons.svg" type="image/svg+xml" style="display:none" aria-hidden="true"></object> <!-- … --> <svg class="icon"><use href="https://downstage.it/downstage-icons.svg#rocket"/></svg>
1. Include the files (local)
CSS always, JS only if you need interactive behaviors.
<link rel="stylesheet" href="downstage.css"> <script src="downstage.js" defer></script>
2. Set the theme
Add data-theme to <html>. Values:
light, dark, auto.
<html data-theme="auto">
3. Use icons
SVG sprite with <use>. Inherits color from text.
<svg class="icon"> <use href="downstage-icons.svg#rocket"/> </svg>
4. Use components
Semantic classes, readable in any template engine.
<button class="btn btn-primary"> <svg class="icon"><use href="...#save"/></svg> Save </button>
02 — Getting started
Starter template
Every downstage page follows the same skeleton: head → icon sprite → navbar → main → footer → scripts. Below is the minimal version and an anatomy breakdown, followed by a richer real-world example.
Minimal blank page
The absolute minimum to get a working page with navbar, content area and footer.
Welcome
Start building your page here.
<!DOCTYPE html>
<html lang="en" data-theme="auto">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Page</title>
<link rel="stylesheet" href="downstage.css">
</head>
<body>
<object data="downstage-icons.svg" type="image/svg+xml"
style="display:none" aria-hidden="true"></object>
<nav class="navbar" id="main-nav">
<div class="navbar-inner">
<a class="navbar-brand" href="/">
<svg class="icon" width="20" height="20">
<use href="downstage-icons.svg#hash" />
</svg>
My App
</a>
<button class="navbar-toggle" aria-label="Open menu"
aria-expanded="false" aria-controls="navbar-menu">
<span></span><span></span><span></span>
</button>
<div class="navbar-menu" id="navbar-menu">
<div class="navbar-menu-scroll">
<a href="/" class="navbar-link active">Home</a>
<a href="/about" class="navbar-link">About</a>
<a href="/contact" class="navbar-link">Contact</a>
<div class="navbar-actions">
<div class="btn-group" role="group" aria-label="Theme">
<button class="btn btn-sm" data-set-theme="light" aria-label="Light">
<svg class="icon"><use href="downstage-icons.svg#sun" /></svg>
</button>
<button class="btn btn-sm" data-set-theme="dark" aria-label="Dark">
<svg class="icon"><use href="downstage-icons.svg#moon" /></svg>
</button>
<button class="btn btn-sm" data-set-theme="auto" aria-label="Auto">Auto</button>
</div>
</div>
</div>
</div>
</div>
</nav>
<main class="container" style="padding-block: var(--space-16);">
<h1>Welcome</h1>
<p class="text-soft mt-4">Start building your page here.</p>
</main>
<footer class="footer">
<div class="footer-inner">
<div class="footer-grid">
<div>
<div class="footer-brand">
<svg class="icon" width="20" height="20">
<use href="downstage-icons.svg#hash" />
</svg>
My App
</div>
<p class="footer-tagline">A short description of your project.</p>
</div>
<div>
<div class="footer-title">Links</div>
<ul class="footer-links">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<div>© 2026 Your Name</div>
</div>
</div>
</footer>
<script src="downstage.js" defer></script>
</body>
</html>
Anatomy — block by block
| Block | Key classes / attributes | What it does |
|---|---|---|
<html data-theme> |
data-theme="auto | light | dark" |
Sets the colour mode. auto follows the OS preference.
downstage.js reads this and enables the theme-switcher buttons. |
<object> sprite |
style="display:none" |
Pre-loads the SVG icon sprite so that every <use href="…#icon">
resolves immediately. Hidden from sight and screen readers. |
.navbar |
.navbar-inner, .navbar-brand, .navbar-toggle,
.navbar-menu |
Sticky top bar. On desktop the links display inline; on mobile they collapse
behind a hamburger (.navbar-toggle) that downstage.js
manages via aria-expanded. |
.navbar-link.active |
.navbar-link + .active |
Marks the current page in the navbar. Add .active to highlight it. |
.navbar-actions |
.btn-group, data-set-theme |
Right-aligned action slot. The data-set-theme buttons
switch light/dark/auto — handled automatically by downstage.js. |
.navbar-dropdown |
<details> + .navbar-dropdown-panel |
Optional dropdown inside the navbar. Uses native <details>
for zero-JS fallback; downstage.js adds close-on-outside-click. |
.container |
style="padding-block: …" |
Centred max-width wrapper for content. Add vertical padding as needed. |
.footer |
.footer-inner, .footer-grid, .footer-brand,
.footer-title, .footer-links, .footer-bottom |
Multi-column footer. .footer-grid auto-flows columns;
.footer-bottom sits at the base (copyright, social icons). |
<script defer> |
defer |
Loads downstage.js without blocking the page. On
DOMContentLoaded it auto-inits every component
(navbar, tabs, accordion, combobox, etc.). |
Paths assume downstage.css, downstage.js, and
downstage-icons.svg are in the same folder as your HTML file.
Adjust href / src if you use a different structure.
Real-world example
A more complete page with a dropdown nav, breadcrumb, hero text, feature cards, a contact form, and a full footer with social icons.
Build something great
Acme Inc. helps teams ship faster with less complexity. No bloat, no lock-in, just clean tools.
Fast
Optimised builds ship in milliseconds. No cold starts, no waiting.
Secure
End-to-end encryption and automatic vulnerability scanning included.
Flexible
Works with any stack. Drop it into your existing project in minutes.
Get in touch
<!DOCTYPE html>
<html lang="en" data-theme="auto">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Acme Inc.</title>
<link rel="stylesheet" href="downstage.css">
</head>
<body>
<object data="downstage-icons.svg" type="image/svg+xml"
style="display:none" aria-hidden="true"></object>
<!-- ====== NAVBAR with dropdown ====== -->
<nav class="navbar" id="main-nav">
<div class="navbar-inner">
<a class="navbar-brand" href="/">
<svg class="icon" width="20" height="20">
<use href="downstage-icons.svg#rocket" />
</svg>
Acme Inc.
</a>
<button class="navbar-toggle" aria-label="Open menu"
aria-expanded="false" aria-controls="navbar-menu">
<span></span><span></span><span></span>
</button>
<div class="navbar-menu" id="navbar-menu">
<div class="navbar-menu-scroll">
<a href="/" class="navbar-link active">Home</a>
<!-- Dropdown menu -->
<details class="navbar-dropdown">
<summary class="navbar-dropdown-summary">
Products
<svg class="icon icon-sm navbar-dropdown-chevron" aria-hidden="true">
<use href="downstage-icons.svg#chevron-down" />
</svg>
</summary>
<div class="navbar-dropdown-panel">
<a href="/widgets" class="navbar-dropdown-link">Widgets</a>
<a href="/gadgets" class="navbar-dropdown-link">Gadgets</a>
<a href="/services" class="navbar-dropdown-link">Services</a>
</div>
</details>
<a href="/pricing" class="navbar-link">Pricing</a>
<a href="/contact" class="navbar-link">Contact</a>
<div class="navbar-actions">
<div class="btn-group" role="group" aria-label="Theme">
<button class="btn btn-sm" data-set-theme="light" aria-label="Light">
<svg class="icon"><use href="downstage-icons.svg#sun" /></svg>
</button>
<button class="btn btn-sm" data-set-theme="dark" aria-label="Dark">
<svg class="icon"><use href="downstage-icons.svg#moon" /></svg>
</button>
<button class="btn btn-sm" data-set-theme="auto" aria-label="Auto">Auto</button>
</div>
</div>
</div>
</div>
</div>
</nav>
<!-- ====== MAIN CONTENT ====== -->
<main class="container" style="padding-block: var(--space-16);">
<!-- Breadcrumb -->
<nav aria-label="Breadcrumb">
<ol class="breadcrumb">
<li><a href="/">
<svg class="icon"><use href="downstage-icons.svg#home" /></svg>
</a></li>
<li>Home</li>
</ol>
</nav>
<!-- Hero -->
<section style="padding-block: var(--space-12);">
<h1>Build something great</h1>
<p class="text-soft mt-4" style="max-width: 540px; font-size: var(--fs-md);">
Acme Inc. helps teams ship faster with less complexity.
No bloat, no lock-in, just clean tools.
</p>
<div class="cluster mt-8">
<a href="/pricing" class="btn btn-primary">
Get started
<svg class="icon"><use href="downstage-icons.svg#arrow-right" /></svg>
</a>
<a href="/docs" class="btn btn-secondary">
<svg class="icon"><use href="downstage-icons.svg#file-text" /></svg>
Documentation
</a>
</div>
</section>
<!-- Feature cards (3 columns) -->
<section style="padding-block: var(--space-12);">
<h2 class="mb-6">Why Acme?</h2>
<div class="grid" style="gap: var(--space-6);">
<div class="col-4">
<div class="card">
<h4>
<svg class="icon" style="vertical-align: -2px;">
<use href="downstage-icons.svg#zap" />
</svg>
Fast
</h4>
<p class="text-soft text-sm mt-2">
Optimised builds ship in milliseconds.
No cold starts, no waiting.
</p>
</div>
</div>
<div class="col-4">
<div class="card">
<h4>
<svg class="icon" style="vertical-align: -2px;">
<use href="downstage-icons.svg#shield" />
</svg>
Secure
</h4>
<p class="text-soft text-sm mt-2">
End-to-end encryption and automatic
vulnerability scanning included.
</p>
</div>
</div>
<div class="col-4">
<div class="card">
<h4>
<svg class="icon" style="vertical-align: -2px;">
<use href="downstage-icons.svg#layers" />
</svg>
Flexible
</h4>
<p class="text-soft text-sm mt-2">
Works with any stack. Drop it into
your existing project in minutes.
</p>
</div>
</div>
</div>
</section>
<!-- Alert -->
<div class="alert alert-info mb-8">
<svg class="icon"><use href="downstage-icons.svg#info" /></svg>
<div>
<strong>Tip:</strong> All colours, spacing, and radii are
CSS custom properties you can override in a single file.
</div>
</div>
<!-- Contact form -->
<section style="padding-block: var(--space-12);">
<h2 class="mb-6">Get in touch</h2>
<form style="max-width: 480px;">
<div class="field">
<label class="label" for="c-name">Name</label>
<input class="input" id="c-name" type="text" placeholder="Jane Doe">
</div>
<div class="field mt-4">
<label class="label" for="c-email">Email</label>
<input class="input" id="c-email" type="email" placeholder="jane@example.com">
</div>
<div class="field mt-4">
<label class="label" for="c-message">Message</label>
<textarea class="input" id="c-message" rows="4" placeholder="How can we help?"></textarea>
</div>
<button class="btn btn-primary mt-6" type="submit">
<svg class="icon"><use href="downstage-icons.svg#send" /></svg>
Send message
</button>
</form>
</section>
</main>
<!-- ====== FOOTER with multiple columns + social ====== -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-grid">
<div>
<div class="footer-brand">
<svg class="icon" width="20" height="20">
<use href="downstage-icons.svg#rocket" />
</svg>
Acme Inc.
</div>
<p class="footer-tagline">
Clean tools for modern teams.
</p>
</div>
<div>
<div class="footer-title">Product</div>
<ul class="footer-links">
<li><a href="/widgets">Widgets</a></li>
<li><a href="/gadgets">Gadgets</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/pricing">Pricing</a></li>
</ul>
</div>
<div>
<div class="footer-title">Company</div>
<ul class="footer-links">
<li><a href="/about">About</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/careers">Careers</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</div>
<div>
<div class="footer-title">Legal</div>
<ul class="footer-links">
<li><a href="/privacy">Privacy</a></li>
<li><a href="/terms">Terms</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<div>© 2026 Acme Inc. · All rights reserved</div>
<div class="footer-social">
<a href="#" aria-label="GitHub">
<svg class="icon"><use href="downstage-icons.svg#github" /></svg>
</a>
<a href="#" aria-label="LinkedIn">
<svg class="icon"><use href="downstage-icons.svg#linkedin" /></svg>
</a>
<a href="#" aria-label="Email">
<svg class="icon"><use href="downstage-icons.svg#mail" /></svg>
</a>
</div>
</div>
</div>
</footer>
<script src="downstage.js" defer></script>
</body>
</html>
Components used in this example
| Component | Classes | Notes |
|---|---|---|
| Navbar dropdown | <details class="navbar-dropdown"> |
Uses native <details>; JS adds close-on-outside-click |
| Breadcrumb | .breadcrumb |
Semantic <nav aria-label="Breadcrumb"> |
| Buttons | .btn .btn-primary, .btn-secondary |
Icon + text; wrap multiple buttons in .cluster for auto-gap |
| Grid + Cards | .grid → .col-4 → .card |
12-column grid; .col-4 = 3 cards per row |
| Alert | .alert .alert-info |
Variants: -success, -danger, -warning, -info |
| Form fields | .field, .label, .input |
Stack .field blocks; works with <input>, <textarea>, <select> |
| Footer social | .footer-social |
Inline icon links in .footer-bottom; use aria-label for a11y |
downstage.css, downstage.js,
downstage-icons.svg) in the same folder,
and open it in a browser.
03 — Tooling
AI & editor guidelines
The repo includes downstage-ai-guidelines.json at the project root: structured conventions for LLMs
(tokens, Downstage API, doc paths, anti-patterns). Point your editor or assistant at it so generated markup matches this design system.
Where the file lives
- Local / vendored copy — same folder as
downstage.css(for exampledownstage-ai-guidelines.json). - Canonical host — when you mirror the release on
downstage.it, use the same path as the CSS, e.g.
https://downstage.it/downstage-ai-guidelines.json(fetch or paste into a rule file).
Cursor
- Project rules — add a rule under
.cursor/rules/(e.g.downstage.mdc) that tells the agent to follow the JSON, or paste thesections/examplestext from the file into that rule. - Global user rules — Cursor Settings → Rules: add a short pointer (“use
downstage-ai-guidelines.jsonin the repo for HTML/CSS/JS conventions”). - Context — with the file in the workspace, you can
@-mention it in chat so it is included in the prompt. - MCP — a static URL is not an MCP server; use a local MCP tool that reads the JSON file or fetches the URL if you need automated injection.
VS Code (GitHub Copilot)
- Custom instructions — add a repo-level instructions file (the path depends on your Copilot version; common choices include
.github/copilot-instructions.mdor the path set under Copilot settings) and summarize the guidelines or link to this page and the JSON. - Workspace context — keep
downstage-ai-guidelines.jsonin the project tree so Copilot can use it when relevant files are open.
Windsurf, JetBrains, other assistants
- AGENTS.md / CLAUDE.md — copy the same conventions into a root markdown file your team uses for agent prompts.
- JetBrains AI — use project-level AI instructions or pin the JSON / a short markdown summary in the repo.
README.md for the same workflow in text form.
04 — Palette
Colors
A warm desaturated neutral scale, two brand colors (sage + taupe) and four semantic ones. They switch automatically in dark mode.
Neutral scale
Brand & Semantic
/* Override brand & semantic colors */
:root {
--brand-primary: #2c5f5d;
--brand-secondary: #8a7e72;
--color-success: #3d8b37;
--color-danger: #c0392b;
--color-warning: #d4a017;
--color-info: #2980b9;
}
/* Neutral scale (50–900) */
:root {
--neutral-50: #fafaf9;
--neutral-100: #f5f5f4;
--neutral-200: #e7e5e4;
--neutral-300: #d6d3d1;
--neutral-400: #a8a29e;
--neutral-500: #78716c;
--neutral-600: #57534e;
--neutral-700: #44403c;
--neutral-800: #292524;
--neutral-900: #1c1917;
}
05 — Typography
Typography
Space Grotesk, self-hosted as a variable font.
Heading 1 — the largest
Heading 2
Heading 3
Heading 4
Body — standard paragraph with comfortable line-height. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Soft — one step lighter, for secondary text.
Muted small — for metadata, labels, captions.
123,456.78 — perfect for numbers.
Press Cmd + K to open search.
<h1>Heading 1 — the largest</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<p>Body — standard paragraph.</p>
<p class="text-soft">Soft — secondary text.</p>
<p class="text-muted text-sm">Muted small — metadata, labels, captions.</p>
<p class="text-mono">123,456.78 — perfect for numbers.</p>
<p>Press <kbd>Cmd</kbd> + <kbd>K</kbd> to open search.</p>
06 — Layout
Grid system
12 columns. Consistent gap. Use .col-N inside .grid.
<div class="grid">
<div class="col-12">.col-12</div>
</div>
<div class="grid">
<div class="col-6">.col-6</div>
<div class="col-6">.col-6</div>
</div>
<div class="grid">
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
</div>
<div class="grid">
<div class="col-3">.col-3</div>
<div class="col-3">.col-3</div>
<div class="col-3">.col-3</div>
<div class="col-3">.col-3</div>
</div>
<div class="grid">
<div class="col-8">.col-8</div>
<div class="col-4">.col-4</div>
</div>
07 — Icons
Icon set
Ship downstage-icons.svg next to your HTML (or fix paths). Prefer a local server so external
<use> resolves; optional <object> helps some browsers load the sprite.
<!-- Optional: preload sprite for external <use> --> <object data="../downstage-icons.svg" type="image/svg+xml" style="display:none" aria-hidden="true"></object> <svg class="icon" width="20" height="20" aria-hidden="true"> <use href="../downstage-icons.svg#check" /> </svg>
190+ minimal stroke icons. All use currentColor
and scale with text size. Use via <use>
or inline.
Loading spinner (.rotate)
Add .rotate to any .icon for a smooth 360° loop.
Works best with circular arrows (e.g. #refresh). Pair with an accessible label:
hide the decorative icon with aria-hidden="true" and set
aria-busy="true" / aria-label on the button or region.
<svg class="icon icon-sm"><use href="downstage-icons.svg#star" /></svg> <!-- sm -->
<svg class="icon"><use href="downstage-icons.svg#star" /></svg> <!-- default -->
<svg class="icon icon-lg"><use href="downstage-icons.svg#star" /></svg> <!-- lg -->
<svg class="icon icon-xl"><use href="downstage-icons.svg#star" /></svg> <!-- xl -->
<svg class="icon icon-lg rotate" aria-hidden="true">
<use href="downstage-icons.svg#refresh" />
</svg>
<button type="button" class="btn btn-primary" disabled aria-busy="true" aria-label="Saving">
<svg class="icon rotate" aria-hidden="true"><use href="downstage-icons.svg#refresh" /></svg>
Save
</button>
Animation: @keyframes ds-icon-spin on
.icon.rotate (0.75s linear infinite). Under prefers-reduced-motion: reduce, one turn takes 1.5s.
All icons
08 — Reference
JavaScript API
Installation
Download the framework files and place them in your project's public directory. The fonts/
folder must sit alongside the CSS file.
<link rel="stylesheet" href="downstage.css">
<script src="downstage.js" defer></script>
That's it. No build tools, no configuration files, no package managers required. Just two files and you're ready.
Configuration
All visual properties are controlled by CSS custom properties (variables). Override them in a separate
file loaded after downstage.css:
:root {
--brand-primary: #2c5f5d;
--radius: 2px;
--container: 800px;
}
- Colors — neutral scale, brand, semantic
- Typography — font families, sizes, weights
- Spacing — 4px-based scale from 0.25rem to 6rem
- Layout — container widths, grid gaps
Theming
Set data-theme on the <html> element. Three modes are supported:
light— always lightdark— always darkauto— followsprefers-color-scheme
The dark theme overrides all neutral, brand, and semantic tokens. Shadows become darker, surfaces shift to warm charcoals, and text becomes light cream.
JavaScript API
downstage.js assigns window.Downstage. Include it with defer; each
submodule runs init() on DOMContentLoaded to wire declarative markup. For content
injected later, call Downstage.*.init() again or mount(selector, options) on the
new root.
Global configuration
| API | Description |
|---|---|
Downstage.configure({ locale, basePath, messages }) |
Passes options to Downstage.i18n.configure: load a locale JSON from
basePath, or merge inline messages for overrides. |
Downstage.i18n |
setLocale(code), getLocale(), t('key', { vars }),
get('path') for nested objects. |
window.__DOWNSTAGE_ICONS_BASE__ |
Optional path prefix for the SVG sprite (documentation pages set e.g.
"../downstage-icons.svg" for <use href>). |
window.__DOWNSTAGE_LOCALE_BASE__ |
Optional folder for JSON locales (default "locales/"). |
Module index
Typical pattern: declarative attributes on a container, or
Downstage.<module>.mount('#id', { … }). Options often mirror
data-* names in camelCase (data-calendar-fetch-url → fetchUrl).
| Module | Declarative hook | Primary API | Documentation |
|---|---|---|---|
theme |
[data-set-theme] |
get(), set('light'|'dark'|'auto') |
Theming |
navbar |
.navbar + toggle |
init() |
— |
tabs |
[data-tabs] |
mount(el) |
Tabs |
accordion |
[data-accordion] (optional ="single") |
init() |
Accordion |
wizard |
[data-wizard], data-wizard-free |
mount(el, { free, onStepChange, onComplete }) → goToStep, next, prev |
Wizard |
formValidate |
form[data-form-validate] |
mount(form, { live, onValid }), validateField(input) |
Form validation |
lightbox |
[data-lightbox="setId"] |
open(nodes, index), close() |
Gallery |
slider |
[data-slider], data-slider-auto |
init() |
Slider |
videoPlayer |
[data-video-player] |
Wraps <video> |
Video |
audioPlayer |
[data-audio-player] |
data-src, data-title, data-artist |
Audio |
uploadDrop |
[data-upload-drop] |
init() |
— |
htmlEditor |
mount / data-html-editor-mount |
mount('#el', { preset, showRawSwitch, toolbarExclude }) |
HTML editor |
combobox |
[data-combobox] |
mount(el, options) |
Combobox |
searchAutocomplete |
often mount-only | mount('#el', { fetchSuggestions, … }) |
Search |
inputAutocomplete |
mount | Inline / modal create flows | Input autocomplete |
tagInput |
[data-tag-input] + data-tag-input-* |
mount(el, options) |
Tag input |
kanban |
[data-kanban] |
mount(el, { fetchUrl, moveUrl, fetchBoard, moveCard, … }) |
Kanban |
dataTable |
[data-data-table] |
mount(el, { mode, columns, rows, fetchRemote }) |
Data table |
calendar |
[data-calendar] |
mount(el, { fetchUrl, defaultView, fetchEvents, … }) |
Calendar |
orderList |
mount | Large options surface — see Data UI page | Order list |
copyField |
[data-copy-field] |
init() |
Copy fields |
passwordInput |
[data-password-toggle] |
init() |
— |
datePicker / dateRange |
[data-datepicker], [data-daterange] |
init() / mount |
Date fields |
Quick calls
Downstage.theme.set('dark');
// Lightbox: pass an array of { src, alt } (galleries usually use data-lightbox instead)
Downstage.lightbox.open([{ src: 'photo.jpg', alt: 'Photo' }], 0);
Downstage.htmlEditor.mount('#editor', { preset: 'demo' });
Downstage.combobox.mount('#cb', { options: [{ value: 'a', label: 'Alpha' }] });
Downstage.kanban.mount('#board', {
fetchUrl: '/api/kanban/board',
moveUrl: '/api/kanban/move',
});
Downstage.dataTable.mount('#table', { mode: 'local', columns: [], rows: [] });
Heavy options (order list, data table remote mode, HTML editor toolbar) are documented on the Data UI and UI Components pages next to each demo.