This is the abridged developer documentation for Airframe # Introduction > Airframe — a structural UI system designed for humans and AI **Airframe** is a structural UI system designed for humans and AI. Import one CSS file. Get layout primitives (`af-stack`, `af-inline`, `af-grid`), a full token layer, accessible patterns, and a readable DOM. No build step. No JavaScript runtime. No framework lock-in. Like an aircraft airframe, it defines the form and integrity of the system. You bring the engine: React, Vue, Angular, AI-generated code, or whatever comes next. ## Structure first [Section titled “Structure first”](#structure-first) Most tools help you style surfaces or assemble components. Airframe starts with the layout contract underneath — stack, inline, grid, tokens, and patterns that keep markup readable. ``` Tailwind → styling utilities Bootstrap → components Airframe → UI structure ``` That is not a brand-new category. It is a different priority: structure before decoration, so the DOM stays understandable when humans or AI change it. ## What it is / isn’t [Section titled “What it is / isn’t”](#what-it-is--isnt) | Airframe is | Airframe is not | | ------------------------------------------------------------------------------- | --------------------------------------- | | Structural primitives and patterns | A component library with JS widgets | | CSS tokens you override at runtime (optional Theme Studio / `af theme` codegen) | A required build step to use the system | | Readable `af-*` markup | Utility soup | | Framework-agnostic CSS | Another React (or Vue) dependency | You keep your framework. Airframe gives the structure that survives it. ## Why start [Section titled “Why start”](#why-start) Readable markup for your team. Predictable patterns for AI. Branding via CSS variables, not a rebuild. Accessibility as infrastructure, not a plugin. [Install Airframe](/docs/installation) · [Read the Manifesto](/docs/manifesto) ## Next Steps [Section titled “Next Steps”](#next-steps) * [Installation](/docs/installation) — get the CSS in your project * [Usage](/docs/usage) — first patterns and primitives * [Layouts](/docs/layouts) — stack, inline, grid, and more * [Tokens & Theming](/docs/theming) — brand it with `--af-*` variables * [Demo](/demo) — an admin UI built only with Airframe classes * [AI Rules](/docs/ai-rules) — the contract for humans and coding agents # Installation > How to install and set up Airframe Install `@airframeui/core`, import one CSS file, and start using patterns. No build plugin required. ## Installation [Section titled “Installation”](#installation) ### 01 — Install the package [Section titled “01 — Install the package”](#01--install-the-package) ``` npm install @airframeui/core # or yarn add @airframeui/core pnpm add @airframeui/core ``` ### 02 — Import the CSS [Section titled “02 — Import the CSS”](#02--import-the-css) Add Airframe to your global stylesheet (recommended): ``` @import "@airframeui/core/core.css"; ``` Or link it from HTML: ``` ``` ### 03 — Start using Airframe [Section titled “03 — Start using Airframe”](#03--start-using-airframe) Use semantic pattern classes immediately: ```

Card Title

Card content goes here.

``` ## Framework guides [Section titled “Framework guides”](#framework-guides) Prefer a framework-specific entrypoint? Use these and skip the generic steps above. ### Next.js [Section titled “Next.js”](#nextjs) Add to `app/globals.css` or `styles/globals.css`: ``` @import "@airframeui/core/core.css"; ``` See the full [Next.js guide](/docs/nextjs). ### React (Vite / Next.js) [Section titled “React (Vite / Next.js)”](#react-vite--nextjs) Add to your main CSS file (e.g. `src/index.css`): ``` @import "@airframeui/core/core.css"; ``` ### Angular [Section titled “Angular”](#angular) Add to `angular.json` under `projects..architect.build.options`: ``` "styles": [ "node_modules/@airframeui/core/core.css", "src/styles.scss" ] ``` Or import in `src/styles.scss`: ``` @import "@airframeui/core/core.css"; ``` See the full [Angular guide](/docs/angular). ### Vue [Section titled “Vue”](#vue) Add to your main CSS file or import from `main.js` / `main.ts`: ``` @import "@airframeui/core/core.css"; ``` ## Next steps [Section titled “Next steps”](#next-steps) * [Usage](/docs/usage) — first patterns and primitives * [Core concepts](/docs/layouts) — layouts, responsive suffix, theming * [Framework Support](/docs/framework-support) — setup overview by framework * [Browser Support](/docs/browser-support) — supported browsers and polyfills # Usage > How to use Airframe in your projects Start using semantic classes immediately after installation. ## Basic Example [Section titled “Basic Example”](#basic-example) ```

Card Title

Card content goes here.

Primary action
``` ### Live Example [Section titled “Live Example”](#live-example) ## Card Title Card content goes here. [Primary action](url) ## Semantic HTML [Section titled “Semantic HTML”](#semantic-html) Airframe styles semantic HTML by default. Many elements work without classes: ```

Main Heading

Section Heading

``` ### Live Example [Section titled “Live Example”](#live-example-1) # Main Heading ## Section Heading EmailSubmit ## Layout Recipes [Section titled “Layout Recipes”](#layout-recipes) Use layout recipes for common patterns: ```

Title

Content

``` ### Live Example [Section titled “Live Example”](#live-example-2) # Title Content Action SaveCancel ## Patterns [Section titled “Patterns”](#patterns) Use pattern classes for common UI structures: ```

Card Title

Card content
Success message
``` ### Live Example [Section titled “Live Example”](#live-example-3) ### Card Title Card content Success message Name ## Responsive Design [Section titled “Responsive Design”](#responsive-design) Use responsive suffixes for breakpoint-specific styles: ```
Item 1
Item 2
Item 3
``` ### Live Example [Section titled “Live Example”](#live-example-4) Item 1 Item 2 Item 3 *Resize your browser to see the grid adapt: 1 column on mobile, 2 on tablet, 3 on desktop.* ## Utilities [Section titled “Utilities”](#utilities) Use utility classes for spacing, typography, and more: ```
Content

Centered muted text

Hidden on small screens
``` ### Live Example [Section titled “Live Example”](#live-example-5) Content with padding and margin Centered muted text Hidden on small screens, visible on medium and up ## Next Steps [Section titled “Next Steps”](#next-steps) * [Layouts](/docs/layouts) - Learn layout patterns * [Theming](/docs/theming) - Customize colors and tokens * Browse [Patterns](/docs/patterns) for more UI structures # AI Rules > Authoritative rules for generating Airframe markup with AI coding agents The authoritative rules ship with `@airframeui/core` as **`@airframeui/core/rules`** (`AIRFRAME_RULES.md`). This page is the docs summary agents and humans should follow when generating markup. ## For LLMs and coding agents [Section titled “For LLMs and coding agents”](#for-llms-and-coding-agents) Prefer these entry points over scraping the whole site: * [`/llms.txt`](/llms.txt) — curated index of documentation sets and package resources * [`/llms-small.txt`](/llms-small.txt) — abridged docs (best default context) * [`/_llms-txt/ai-rules.txt`](/_llms-txt/ai-rules.txt) — this page + AI engineering notes * [`/_llms-txt/getting-started.txt`](/_llms-txt/getting-started.txt) — install, usage, tokens, layouts After `npm install @airframeui/core`, load in-project resources: ``` // JSON (safe to import in Node / bundlers) import catalog from '@airframeui/core/catalog'; // component metadata import classes from '@airframeui/core/classes'; // class reference import examples from '@airframeui/core/examples'; // code examples // Markdown — resolve the package export and read as text (do not assume a JS default export) // @airframeui/core/rules → AIRFRAME_RULES.md // @airframeui/core/ai → AI_INTEGRATION.md ``` ## Non-negotiable rules [Section titled “Non-negotiable rules”](#non-negotiable-rules) * **Semantic HTML first** — ` ``` ### Semantic typography first [Section titled “Semantic typography first”](#semantic-typography-first) ```

Title

Body text

Visually H1, semantically H2

Caption

Title

``` ## Related tooling [Section titled “Related tooling”](#related-tooling) * [VS Code Extension](/docs/vscode-extension) — IntelliSense for tokens and classes * [ESLint plugin](/docs/eslint-plugin) — catch Tailwind/Bootstrap leftovers and prefer layout recipes * [AI and Human Engineering](/docs/ai-and-human-engineering) — why the structural contract exists # Tokens Override **hex primitives** in `:root`: ``` :root { --af-base-primary: #018183; } ``` Interaction is derived via `color-mix()`: ``` :root { --af-hover-mix: 12%; --af-active-mix: 18%; } ``` For dark mode and theme overrides, see [Theming](/docs/theming#dark-mode). ## Color Palette [Section titled “Color Palette”](#color-palette) Airframe ships with a calm, modern default palette designed for product UI. Neutrals form the structure—they provide the foundation for surfaces, borders, and text. Accent colors indicate motion and intent—they signal actions, states, and meaning. Everything is overridable. Override primitives in `:root` to change the entire system, or adjust semantic tokens for targeted changes. ### Color Primitives [Section titled “Color Primitives”](#color-primitives) ``` :root { /* Accent colors */ --af-base-primary: #4663f5; --af-base-secondary: #22d3ee; --af-base-tertiary: #111827; --af-base-success: #22c55e; --af-base-warning: #fbbf24; --af-base-danger: #dc2626; --af-base-info: #38bdf8; /_ Neutrals _/ --af-base-white: #ffffff; --af-base-black: #000000; --af-base-neutral-50: #f8fafc; --af-base-neutral-100: #f1f5f9; --af-base-neutral-200: #e2e8f0; --af-base-neutral-300: #cbd5e1; --af-base-neutral-400: #94a3b8; --af-base-neutral-500: #64748b; --af-base-neutral-600: #475569; --af-base-neutral-700: #334155; --af-base-neutral-800: #1f2937; --af-base-neutral-900: #111827; } ``` ### Global Color Mix Knobs [Section titled “Global Color Mix Knobs”](#global-color-mix-knobs) These control how interaction states are derived via `color-mix()`: ``` :root { --af-hover-mix: 12%; /* Hover state color mix */ --af-active-mix: 18%; /* Active state color mix */ --af-soft-mix: 12%; /* Soft variant color mix (lighter) */ --af-hard-mix: 45%; /* Hard variant color mix (darker; AA text on soft) */ --af-border-mix: 22%; /* Border color mix */ } ``` Soft intent surfaces (`*-soft`) pair with hard text (`*-hard`) in badges, chips, and KPI deltas so small text meets WCAG AA (4.5:1). Mid-tone intent colors (`--af-color-success`, etc.) stay vivid for fills and icons — do not use them as small text on soft tints. ### Action color (theme-overridable) [Section titled “Action color (theme-overridable)”](#action-color-theme-overridable) The **action** token (`--af-color-action`) is the semantic “main CTA/brand color” used for buttons, links, focus rings, and other interactive elements. It defaults to primary; **`--af-color-primary`** (and `--af-color-on-primary`) are resolved from action, so all existing components that use primary automatically respect the override. Override action per theme when you want a different accent in dark or high-contrast modes. **For high-contrast themes, ensure colors meet WCAG 2.2 AA contrast requirements** (4.5:1 for normal text, 3:1 for large text): ``` /* Dark mode */ @media (prefers-color-scheme: dark) { :root { --af-color-action--dark: #60a5fa; --af-color-on-action--dark: #0f172a; } } /_ Or when using a manual dark theme class _/ [data-theme="dark"], .dark { --af-color-action--dark: #60a5fa; --af-color-on-action--dark: #0f172a; } /_ High-contrast light - use stronger colors for better contrast _/ :root { --af-color-action--hc-light: #0066cc; /_ Stronger blue meets WCAG AA _/ --af-color-on-action--hc-light: #ffffff; } /_ High-contrast dark - lighter colors for dark backgrounds _/ :root { --af-color-action--hc-dark: #60a5fa; /_ Lighter blue for dark mode _/ --af-color-on-action--hc-dark: #000000; } ``` **Note:** High-contrast overrides work automatically with system `prefers-contrast: more` or `prefers-contrast: high` preference. No media queries needed—just define the `--hc-light` and `--hc-dark` tokens in `:root`. See [High Contrast Theming](/docs/theming#high-contrast) for complete examples. Derived tokens (`--af-color-action-hover`, `-action-active`, `-action-soft`, `-action-hard`) are computed from the resolved action via `color-mix()`, so they stay consistent when you override. ## Typography Tokens [Section titled “Typography Tokens”](#typography-tokens) Typography is driven by semantic tokens so brands can override safely: ### Font Families [Section titled “Font Families”](#font-families) ``` :root { /* Font primitives */ --af-base-font-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; --af-base-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /_ Semantic font tokens _/ --af-font-primary: var(--af-base-font-sans); /_ Primary font (used for body text by default) _/ --af-font-heading: var(--af-font-primary); /_ Heading font (applied to h1-h6, .af-text-h_, .af-text-display) _/ --af-font-body: var(--af-base-font-sans); /_ Body text font _/ --af-font-code: var(--af-base-font-mono); /_ Code font _/ --af-font-mono: var(--af-base-font-mono); /_ Monospace font */ } ``` **Customizing fonts:** ``` :root { /* Use custom web fonts */ --af-font-primary: 'Inter', 'Roboto', sans-serif; --af-font-heading: 'Playfair Display', serif; /* Different font for headings */ --af-font-body: var(--af-font-primary); /* Body uses primary */ } ``` ### Type Scale [Section titled “Type Scale”](#type-scale) ``` :root { /* Core type scale */ --af-text-xs: 0.75rem; --af-text-sm: 0.875rem; --af-text-md: 1rem; --af-text-lg: 1.125rem; --af-text-xl: 1.25rem; --af-text-2xl: 1.5rem; --af-text-3xl: 1.875rem; /_ Leading (line-height) - typography term for vertical spacing between lines _/ /_ Use --af-leading-_ tokens; these map to CSS line-height property */ --af-leading-tight: 1.1; --af-leading-normal: 1.5; --af-leading-loose: 1.7; /_ Weights _/ --af-weight-regular: 400; --af-weight-medium: 500; --af-weight-semibold: 600; --af-weight-bold: 700; --af-weight-extrabold: 800; } ``` ### Role Tokens (Override-Friendly) [Section titled “Role Tokens (Override-Friendly)”](#role-tokens-override-friendly) Typography role tokens map semantic roles (h1, h2, body, etc.) to type scale values. Override these to customize typography without touching primitives: ``` :root { /* Display type */ --af-type-display-size: var(--af-text-3xl); --af-type-display-weight: var(--af-weight-bold); --af-type-display-leading: var(--af-leading-tight); /_ Heading sizes _/ --af-type-h1-size: var(--af-text-3xl); --af-type-h2-size: var(--af-text-2xl); --af-type-h3-size: var(--af-text-xl); --af-type-h4-size: var(--af-text-lg); --af-type-h5-size: var(--af-text-md); --af-type-h6-size: var(--af-text-sm); /_ Heading weights _/ --af-type-h1-weight: var(--af-weight-semibold); --af-type-h2-weight: var(--af-weight-semibold); --af-type-h3-weight: var(--af-weight-semibold); --af-type-h4-weight: var(--af-weight-semibold); --af-type-h5-weight: var(--af-weight-semibold); --af-type-h6-weight: var(--af-weight-semibold); /_ Heading leading _/ --af-type-h1-leading: var(--af-leading-tight); --af-type-h2-leading: var(--af-leading-tight); --af-type-h3-leading: var(--af-leading-tight); --af-type-h4-leading: var(--af-leading-normal); --af-type-h5-leading: var(--af-leading-normal); --af-type-h6-leading: var(--af-leading-normal); /_ Heading letter spacing _/ --af-type-h1-tracking: -0.02em; --af-type-h2-tracking: -0.01em; --af-type-h3-tracking: 0em; --af-type-h4-tracking: 0em; --af-type-h5-tracking: 0em; --af-type-h6-tracking: 0em; /_ Body and caption _/ --af-type-body-size: var(--af-text-md); --af-type-body-weight: var(--af-weight-regular); --af-type-body-leading: var(--af-leading-normal); --af-type-caption-size: var(--af-text-sm); --af-type-caption-weight: var(--af-weight-regular); --af-type-caption-leading: var(--af-leading-normal); /_ Semantic typography roles _/ --af-text-body-size: var(--af-text-md); --af-text-body-leading: var(--af-leading-normal); --af-text-heading-leading: var(--af-leading-tight); --af-text-heading-weight: var(--af-weight-semibold); } ``` ## Spacing Tokens [Section titled “Spacing Tokens”](#spacing-tokens) The space scale provides consistent spacing values used throughout the system: ``` :root { --af-space-0: 0px; --af-space-1: 4px; --af-space-2: 8px; --af-space-3: 12px; --af-space-4: 16px; --af-space-5: 24px; --af-space-6: 32px; --af-space-7: 40px; --af-space-8: 48px; } ``` These tokens are used by spacing utilities (`af-p-*`, `af-m-*`, `af-gap-*`) and layout recipes. ## Border Radius Tokens [Section titled “Border Radius Tokens”](#border-radius-tokens) Radius tokens control the roundness of corners: ``` :root { --af-radius-0: 0px; --af-radius-sm: 6px; --af-radius-md: 10px; --af-radius-lg: 16px; --af-radius-xl: 24px; --af-radius-full: 9999px; } ``` ## Breakpoint Tokens [Section titled “Breakpoint Tokens”](#breakpoint-tokens) Breakpoint tokens define responsive breakpoints used by responsive suffixes (`@md`, `@lg`, etc.): ``` :root { --af-bp-xs: 360px; --af-bp-sm: 640px; --af-bp-md: 768px; --af-bp-lg: 1024px; --af-bp-xl: 1280px; --af-bp-2xl: 1536px; } ``` ## Shadow Tokens [Section titled “Shadow Tokens”](#shadow-tokens) Shadow tokens provide consistent elevation: ``` :root { --af-shadow-sm: 0 1px 2px rgba(0,0,0,.06); --af-shadow-md: 0 6px 16px rgba(0,0,0,.10); --af-shadow-lg: 0 16px 40px rgba(0,0,0,.14); } ``` ## Z-Index Tokens [Section titled “Z-Index Tokens”](#z-index-tokens) Z-index tokens provide a consistent layering system: ``` :root { --af-z-base: 0; --af-z-dropdown: 1000; --af-z-sticky: 1100; --af-z-overlay: 1200; --af-z-modal: 1300; --af-z-toast: 1400; } ``` ## Border Tokens [Section titled “Border Tokens”](#border-tokens) Border tokens control border width and hit target sizes: ``` :root { --af-border-width: 2px; --af-hit-size: 2.75rem; /* Minimum touch target size */ } ``` ## Layout Tokens [Section titled “Layout Tokens”](#layout-tokens) Layout tokens control container widths and layout spacing: ``` :root { --af-layout-gap: var(--af-space-4); --af-container-padding-x: var(--af-space-4); --af-container-max-w: 90em; /* 1440px - default container */ --af-container-max-w-xs: 25rem; /* 400px */ --af-container-max-w-sm: 40rem; /* 640px */ --af-container-max-w-md: 48rem; /* 768px */ --af-container-max-w-lg: 64rem; /* 1024px */ --af-container-max-w-xl: 80rem; /* 1280px */ --af-container-max-w-2xl: 96rem; /* 1536px */ } ``` ## Component Tokens [Section titled “Component Tokens”](#component-tokens) Component tokens are a thin, override-friendly layer for common sizing tweaks. They sit on top of global tokens so you can adjust buttons and form controls without rewriting styles. ### Shared Control Tokens [Section titled “Shared Control Tokens”](#shared-control-tokens) ``` :root { --af-control-min-height: auto; --af-control-radius: var(--af-radius-xl); --af-control-padding-y: var(--af-space-2); --af-control-padding-x: var(--af-space-3); --af-control-border: var(--af-color-border); /_ Choice controls (checkbox, radio, switch track height) _/ --af-choice-size: 1.5rem; --af-switch-height: var(--af-choice-size); --af-switch-width-ratio: 0.8; } ``` Checkbox and radio use `--af-choice-size`. Switches use `--af-switch-height` (defaults to choice size) and `--af-switch-width-ratio` for track width. ### Button Tokens [Section titled “Button Tokens”](#button-tokens) ``` :root { /* Button sizing */ --af-btn-min-height: var(--af-control-min-height); --af-btn-radius: var(--af-radius-full); --af-btn-padding-y: var(--af-control-padding-y); --af-btn-padding-x: var(--af-space-4); --af-btn-gap: var(--af-space-2); --af-btn-icon-size: 1.25em; --af-btn-font-weight: var(--af-weight-medium); --af-btn-border-width: var(--af-border-width); /_ Button colors (primary/default) _/ --af-btn-default-bg: var(--af-color-primary); --af-btn-default-color: var(--af-color-on-primary); --af-btn-default-hover: var(--af-color-primary-hover); --af-btn-default-active: var(--af-color-primary-active); /_ Button colors (secondary) _/ --af-btn-secondary-bg: var(--af-base-secondary); --af-btn-secondary-color: var(--af-color-on-secondary); --af-btn-secondary-hover: color-mix(in srgb, var(--af-btn-secondary-bg), black 4%); --af-btn-secondary-active: color-mix(in srgb, var(--af-btn-secondary-bg), black 8%); /_ Button colors (outline) _/ --af-btn-outline-color: var(--af-color-primary); --af-btn-outline-border: var(--af-color-primary); --af-btn-outline-hover: var(--af-btn-outline-border); --af-btn-outline-active: color-mix(in srgb, var(--af-color-primary), var(--af-color-surface-primary) 84%); } ``` ### Input Tokens [Section titled “Input Tokens”](#input-tokens) ``` :root { --af-input-min-height: var(--af-control-min-height); --af-input-radius: var(--af-control-radius); --af-input-padding-y: var(--af-control-padding-y); --af-input-padding-x: var(--af-control-padding-x); --af-input-font-size: var(--af-text-md); --af-input-leading: var(--af-leading-normal); --af-input-placeholder-color: var(--af-color-text-muted); } ``` ### Link Tokens [Section titled “Link Tokens”](#link-tokens) ``` :root { --af-link-primary: var(--af-color-primary); --af-link-hover-primary: var(--af-color-primary-hover); } ``` ### Card Tokens [Section titled “Card Tokens”](#card-tokens) ``` :root { --af-card-radius: var(--af-radius-lg); --af-card-padding: var(--af-space-4); --af-card-shadow: var(--af-shadow-sm); --af-card-shadow-hover: var(--af-shadow-md); } ``` ### Focus Ring Tokens [Section titled “Focus Ring Tokens”](#focus-ring-tokens) ``` :root { --af-focus-ring-color: var(--af-color-focus); --af-focus-ring-width: 2px; --af-focus-ring-offset: 2px; } ``` ### Example Override [Section titled “Example Override”](#example-override) ``` :root { --af-control-min-height: 3rem; --af-btn-gap: 0.75rem; --af-input-placeholder-color: rgba(0, 0, 0, 0.45); } ``` ## Motion Tokens [Section titled “Motion Tokens”](#motion-tokens) Motion tokens provide consistent timing for transitions and animations, with **automatic reduced motion support** built-in. ### Duration Variables [Section titled “Duration Variables”](#duration-variables) **Transition durations** (for CSS transitions): ``` :root { --af-duration-fast: 120ms; /* Quick interactions */ --af-duration-md: 200ms; /* Standard transitions */ --af-duration-slow: 320ms; /* Deliberate changes */ } ``` **Animation durations** (for keyframe animations): ``` :root { --af-animation-duration-fast: 200ms; /* Quick animations */ --af-animation-duration-md: 400ms; /* Standard animations */ --af-animation-duration-slow: 600ms; /* Slower animations */ --af-animation-duration-slower: 1500ms; /* Very slow animations */ } ``` ### Easing Functions [Section titled “Easing Functions”](#easing-functions) ``` :root { --af-ease-standard: cubic-bezier(.2, .0, .2, 1); /* Default easing */ --af-ease-emphasized: cubic-bezier(.2, .0, 0, 1); /* More pronounced */ --af-ease-in: cubic-bezier(.4, .0, 1, 1); /* Ease in */ --af-ease-out: cubic-bezier(.0, .0, .2, 1); /* Ease out */ --af-ease-in-out: cubic-bezier(.4, .0, .2, 1); /* Ease in-out */ --af-ease-linear: linear; /* Linear */ } ``` ### Usage Examples [Section titled “Usage Examples”](#usage-examples) **Transitions:** ``` /* Button hover transition */ .af-btn { transition: background-color var(--af-duration-fast) var(--af-ease-standard); } /_ Card shadow transition _/ .af-card { transition: box-shadow var(--af-duration-md) var(--af-ease-out); } /_ Multiple properties _/ .element { transition: background-color var(--af-duration-fast) var(--af-ease-standard), transform var(--af-duration-md) var(--af-ease-emphasized); } ``` **Animations:** ``` /* Spinner animation */ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .af-spinner { animation: spin var(--af-animation-duration-md) var(--af-ease-linear) infinite; } /_ Skeleton loading animation _/ @keyframes skeleton-load { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .af-skeleton { animation: skeleton-load var(--af-animation-duration-slower) var(--af-ease-in-out) infinite; } ``` ### Reduced Motion Support [Section titled “Reduced Motion Support”](#reduced-motion-support) All motion tokens **automatically respect** the user’s `prefers-reduced-motion` preference. When reduced motion is enabled, all durations are set to `0.01ms` (effectively instant). **No additional code needed** - just use the tokens: ``` /* This automatically respects reduced motion */ .button { transition: background-color var(--af-duration-fast) var(--af-ease-standard); } /_ This also respects reduced motion _/ .spinner { animation: spin var(--af-animation-duration-md) linear infinite; } ``` **Customizing motion tokens:** ``` :root { /* Override default durations */ --af-duration-fast: 100ms; --af-animation-duration-slow: 800ms; /_ Custom easing _/ --af-ease-standard: cubic-bezier(0.4, 0, 0.2, 1); } ``` **Note:** The reduced motion override still applies even when you customize these values, ensuring accessibility is maintained. # Theming > Customize colors, tokens, and themes in Airframe Airframe uses tokens as CSS variables. Override them directly in CSS—no build step required. ## Theme Studio [Section titled “Theme Studio”](#theme-studio) Need to map an existing design system? Use **[Theme Studio](/theme-studio)** to upload Tokens Studio / DTCG / CSS / Figma Variables, preview on real patterns, lint unknown tokens, and export `theme.css`. CLI equivalent (via `@airframeui/build`): ``` npx af theme generate --from ./tokens.json -o theme.css npx af theme lint theme.css ``` AI / MCP: install `@airframeui/mcp` and use `generate_theme` → `lint_theme`. See `@airframeui/theme/rules` and [Build Tool](/docs/advanced/build#af-theme-theme-generation). ## Color Tokens [Section titled “Color Tokens”](#color-tokens) ### Override Primitives (Simplest) [Section titled “Override Primitives (Simplest)”](#override-primitives-simplest) Override **hex primitives** (`--af-base-*`) in `:root` for simple, global brand color changes. This is the easiest approach and changes everything that uses that color: ``` :root { --af-base-primary: #018183; --af-base-secondary: #6b7280; --af-base-success: #10b981; --af-base-danger: #ef4444; --af-base-warning: #f59e0b; --af-base-info: #3b82f6; } ``` **When to use:** Simple brand color swaps, global changes, when you want the same color across all themes. **Limitation:** Primitives are shared across all themes, so you can’t have different colors for light/dark/high-contrast. ### Override Semantic Tokens (Theme-Specific) [Section titled “Override Semantic Tokens (Theme-Specific)”](#override-semantic-tokens-theme-specific) Override **semantic tokens** (`--af-color-*`) with theme suffixes (`--dark`, `--hc-light`, `--hc-dark`) for per-theme control: ``` :root { /* Different primary color per theme */ --af-color-primary--dark: #38bdf8; /* Lighter blue in dark mode */ --af-color-action--hc-light: #0066cc; /* Stronger blue for high contrast */ } ``` **When to use:** Different colors per theme, accessibility adjustments (like stronger colors for high-contrast), fine-grained control. **See:** [Dark Mode](#dark-mode) and [High Contrast](#high-contrast) sections for complete examples. ### Interaction States [Section titled “Interaction States”](#interaction-states) Interaction states and soft/hard variants are derived via `color-mix()`: ``` :root { --af-hover-mix: 12%; --af-active-mix: 18%; --af-soft-mix: 12%; --af-hard-mix: 45%; /* Dark enough for AA text on soft intent surfaces */ } ``` Badges, chips, and KPI deltas use `*-hard` text on `*-soft` backgrounds. Keep `--af-hard-mix` high enough that success/warning/info hard text clears 4.5:1 on soft. ## Dark Mode [Section titled “Dark Mode”](#dark-mode) Airframe ships with dark tokens and follows system preference by default. ### Default Behavior [Section titled “Default Behavior”](#default-behavior) When you import the core CSS, dark mode follows `prefers-color-scheme` automatically. No extra configuration is required. ### Force a Theme [Section titled “Force a Theme”](#force-a-theme) Dark mode follows system preference by default. To override the system preference, set dark mode on the root element using one of these methods: * **`data-theme` attribute**: Standard data attribute * **`.dark` class**: CSS class ``` ... ... ... ``` ### Custom Dark Mode Colors [Section titled “Custom Dark Mode Colors”](#custom-dark-mode-colors) Override dark mode colors using the `--dark` suffix pattern on **semantic tokens** (`--af-color-*`). This works regardless of how dark mode is applied (media query, class, or data attribute): ``` :root { /* Override dark mode colors - works with any dark mode implementation */ /* Base surfaces */ --af-color-background--dark: #0a0a0a; --af-color-surface-primary--dark: #0a0a0a; /* Text */ --af-color-text--dark: #ffffff; /* Borders */ --af-color-border--dark: #333333; /* Intent (primary) */ --af-color-primary--dark: #38bdf8; } ``` **Note:** You can also override primitives (`--af-base-primary`) for a global change, but semantic tokens with `--dark` suffix give you theme-specific control. See [Color Tokens](#color-tokens) for when to use each approach. ## High Contrast [Section titled “High Contrast”](#high-contrast) **Accessibility is foundational to Airframe.** High-contrast themes ensure your UI is accessible to users with low vision, color blindness, or who need higher contrast for readability. High-contrast tokens are applied **automatically** when a user enables high contrast in their OS settings. If both dark mode and high contrast are enabled, the high-contrast dark tokens apply. ### Customizing High Contrast Colors [Section titled “Customizing High Contrast Colors”](#customizing-high-contrast-colors) Airframe detects the system `prefers-contrast: more` or `prefers-contrast: high` preference and automatically applies high-contrast semantic tokens. Override these tokens to customize colors while maintaining accessibility. Override high contrast colors using the `--hc-light` and `--hc-dark` suffix patterns on **semantic tokens** (`--af-color-*`). You can also override primitives (`--af-base-primary--hc-light` / `--af-base-primary--hc-dark`) for brand color changes that apply across all semantic tokens. ``` :root { /* High contrast light mode - override semantic tokens */ --af-color-background--hc-light: #ffffff; --af-color-surface-primary--hc-light: #ffffff; --af-color-text--hc-light: #000000; --af-color-text-muted--hc-light: #333333; --af-color-border--hc-light: #000000; --af-color-border-strong--hc-light: #000000; /_ Override action/primary colors for high contrast _/ --af-color-action--hc-light: #0066cc; /_ Stronger blue for better contrast _/ --af-color-on-action--hc-light: #ffffff; /_ High contrast dark mode - override semantic tokens _/ --af-color-background--hc-dark: #000000; --af-color-surface-primary--hc-dark: #1a1a1a; --af-color-text--hc-dark: #ffffff; --af-color-text-muted--hc-dark: #cccccc; --af-color-border--hc-dark: #ffffff; --af-color-border-strong--hc-dark: #ffffff; /_ Override action/primary colors for high contrast dark _/ --af-color-action--hc-dark: #60a5fa; /_ Lighter blue for dark backgrounds _/ --af-color-on-action--hc-dark: #000000; } ``` **Important:** Always verify contrast ratios meet WCAG 2.2 AA requirements (4.5:1 for normal text, 3:1 for large text and UI components). Use a [contrast checker](/resources/accessibility/color-contrast) before deploying. ### Available High Contrast Override Tokens [Section titled “Available High Contrast Override Tokens”](#available-high-contrast-override-tokens) | Token | HC Light (`--hc-light`) | HC Dark (`--hc-dark`) | | -------------------- | ---------------------------------------- | --------------------------------------- | | **Surface** | | | | background | `--af-color-background--hc-light` | `--af-color-background--hc-dark` | | surface-primary | `--af-color-surface-primary--hc-light` | `--af-color-surface-primary--hc-dark` | | surface-secondary | `--af-color-surface-secondary--hc-light` | `--af-color-surface-secondary--hc-dark` | | surface-tertiary | `--af-color-surface-tertiary--hc-light` | `--af-color-surface-tertiary--hc-dark` | | **Text** | | | | text | `--af-color-text--hc-light` | `--af-color-text--hc-dark` | | text-muted | `--af-color-text-muted--hc-light` | `--af-color-text-muted--hc-dark` | | text-inverse | `--af-color-text-inverse--hc-light` | `--af-color-text-inverse--hc-dark` | | **Border** | | | | border | `--af-color-border--hc-light` | `--af-color-border--hc-dark` | | border-strong | `--af-color-border-strong--hc-light` | `--af-color-border-strong--hc-dark` | | **Action / primary** | | | | action | `--af-color-action--hc-light` | `--af-color-action--hc-dark` | | on-action | `--af-color-on-action--hc-light` | `--af-color-on-action--hc-dark` | | **Intent (on-)** | | | | on-primary | `--af-color-on-primary--hc-light` | `--af-color-on-primary--hc-dark` | | on-secondary | `--af-color-on-secondary--hc-light` | `--af-color-on-secondary--hc-dark` | | on-success | `--af-color-on-success--hc-light` | `--af-color-on-success--hc-dark` | | on-warning | `--af-color-on-warning--hc-light` | `--af-color-on-warning--hc-dark` | | on-danger | `--af-color-on-danger--hc-light` | `--af-color-on-danger--hc-dark` | | on-info | `--af-color-on-info--hc-light` | `--af-color-on-info--hc-dark` | ### Testing High Contrast [Section titled “Testing High Contrast”](#testing-high-contrast) Enable high contrast in your OS (Windows: Settings → Ease of Access → High contrast) or use browser DevTools to simulate `prefers-contrast: more`. Verify all text meets WCAG 2.2 AA (4.5:1 for normal text, 3:1 for large text) and test in both light and dark modes. ## Typography Tokens [Section titled “Typography Tokens”](#typography-tokens) Typography is driven by semantic tokens so brands can override safely: ### Font Families [Section titled “Font Families”](#font-families) ``` :root { /* Override semantic font tokens */ --af-font-primary: 'Inter', 'Roboto', sans-serif; --af-font-heading: 'Playfair Display', serif; --af-font-body: var(--af-font-primary); --af-font-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; } ``` ### Type Scale [Section titled “Type Scale”](#type-scale) ``` :root { /* Override type scale, leading (line-height), and weights */ --af-text-lg: 1.125rem; --af-leading-normal: 1.5; --af-weight-medium: 500; } ``` ## Component Tokens [Section titled “Component Tokens”](#component-tokens) Component tokens provide override-friendly sizing for buttons, inputs, and other controls: ``` :root { /* Shared control tokens */ --af-control-min-height: 3rem; --af-control-radius: var(--af-radius-md); /_ Choice controls (checkbox, radio, switch track) _/ --af-choice-size: 1.5rem; --af-switch-height: var(--af-choice-size); --af-switch-width-ratio: 0.8; /_ Button-specific _/ --af-btn-gap: 0.75rem; --af-btn-padding-x: var(--af-space-4); /_ Input-specific _/ --af-input-placeholder-color: rgba(0, 0, 0, 0.45); } ``` ## Motion Tokens [Section titled “Motion Tokens”](#motion-tokens) Motion tokens provide consistent timing for transitions and animations, with **automatic reduced motion support**: ``` :root { /* Duration */ --af-duration-fast: 120ms; --af-duration-md: 200ms; /_ Easing _/ --af-ease-standard: cubic-bezier(.2, .0, .2, 1); --af-ease-emphasized: cubic-bezier(.2, .0, 0, 1); } ``` ## Complete Example [Section titled “Complete Example”](#complete-example) ``` :root { /* Colors */ --af-base-primary: #0ea5e9; /* Global brand color */ --af-hover-mix: 12%; --af-hard-mix: 45%; /* Hard text on soft surfaces (AA) */ /* Override dark mode colors */ --af-color-background--dark: #0a0a0a; --af-color-primary--dark: #38bdf8; /* Different primary in dark mode */ /_ Typography _/ --af-font-heading: ui-sans-serif, system-ui, sans-serif; --af-text-lg: 1.1875rem; /_ Components _/ --af-control-min-height: 2.5rem; --af-choice-size: 1.375rem; --af-btn-radius: var(--af-radius-lg); } ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [Tokens Reference](/docs/tokens) - Complete token documentation * [Advanced Overrides](/docs/advanced/overrides) - Deep customization # Layouts Layout recipes provide consistent patterns for organizing content. They replace verbose utility classes with semantic, readable class names. ## Stack [Section titled “Stack”](#stack) Vertical stacking layout for arranging items in a column. ### Class Reference [Section titled “Class Reference”](#class-reference) | Class | Purpose | Gap Size | Example | | ------------- | ---------------------- | ----------------- | --------------------------- | | `af-stack` | Default vertical stack | Medium (`gap-md`) | `
` | | `af-stack-sm` | Small gap stack | Small (`gap-sm`) | `
` | | `af-stack-md` | Medium gap stack | Medium (`gap-md`) | `
` | | `af-stack-lg` | Large gap stack | Large (`gap-lg`) | `
` | | `af-stack-xl` | Extra large gap stack | XL (`gap-xl`) | `
` | ### Basic Stack [Section titled “Basic Stack”](#basic-stack) Code Live ```
Item 1
Item 2
Item 3
``` Item 1 Item 2 Item 3 ### Stack Sizes [Section titled “Stack Sizes”](#stack-sizes) Code Live ```
Small spacing
Default spacing (md)
Medium spacing (same as default)
Large spacing
``` Small gap Small gap Default gap Default gap Large gap Large gap ### Live Examples [Section titled “Live Examples”](#live-examples) Basic stack (default gap-md): Item 1 Item 2 Item 3 Stack sizes: Small gap Small gap Default gap Default gap Large gap Large gap ## Inline [Section titled “Inline”](#inline) Horizontal layout with wrapping for arranging items in a row. ### Class Reference [Section titled “Class Reference”](#class-reference-1) | Class | Purpose | Gap Size | Example | | -------------- | ----------------------- | ----------------- | ---------------------------- | | `af-inline` | Default horizontal wrap | Medium (`gap-md`) | `
` | | `af-inline-sm` | Small gap inline | Small (`gap-sm`) | `
` | | `af-inline-md` | Medium gap inline | Medium (`gap-md`) | `
` | | `af-inline-lg` | Large gap inline | Large (`gap-lg`) | `
` | | `af-inline-xl` | Extra large gap inline | XL (`gap-xl`) | `
` | ### Basic Inline [Section titled “Basic Inline”](#basic-inline) Code Live ```
``` Button 1 Button 2 Button 3 ### Inline Sizes [Section titled “Inline Sizes”](#inline-sizes) Code Live ```
Small spacing
Default spacing (md)
Large spacing
XL spacing
``` Small Gap Default Gap Large Gap XL Gap ### Inline with Justify Content [Section titled “Inline with Justify Content”](#inline-with-justify-content) Code Live ```
Start aligned
Center aligned
End aligned
Space between
``` Start Aligned Center Aligned End Aligned Space Between ### Live Examples [Section titled “Live Examples”](#live-examples-1) Basic inline (default gap-md): Button 1Button 2Button 3 Inline sizes: SmallGap DefaultGap LargeGap XLGap Justify content: StartAligned CenterAligned EndAligned SpaceBetween ## Cluster, Spread & Center [Section titled “Cluster, Spread & Center”](#cluster-spread--center) **Layout primitives vs Display utilities:** `af-cluster`, `af-spread`, and `af-center` are **semantic layout recipes** — each combines display, alignment, and gap in one class. They live in [Layouts](/docs/layouts) (this page). The [Display & Alignment](/docs/utilities/display) utilities (`af-flex`, `af-justify-*`, `af-items-*`) are **low-level building blocks** — use them when you need custom combinations (e.g. `af-inline af-justify-end`). Prefer layout recipes first; reach for utilities when you need fine-grained control. | Recipe | Equivalent utilities | Use when | | ------------ | ----------------------------------------------------------------------------------- | -------------------------------- | | `af-cluster` | `af-inline af-items-center af-gap-md` | Tags, chips, grouped buttons | | `af-spread` | `af-inline af-items-center af-justify-between` | Header left/right, space-between | | `af-center` | `af-flex af-justify-center af-items-center` or `display: grid; place-items: center` | Centering content on both axes | Cluster and spread are lightweight inline layout recipes for common alignment patterns. Default to these semantic recipes, and use explicit alignment utilities when you need fine-grained control. ### Class Reference [Section titled “Class Reference”](#class-reference-2) | Class | Purpose | Example | | ------------ | ---------------------------------------- | -------------------------- | | `af-cluster` | Inline cluster (wrap + center alignment) | `
` | | `af-spread` | Inline spread (space-between) | `
` | ### Examples [Section titled “Examples”](#examples) Code Live ```
Tag 1 Tag 2 Tag 3
Left Right
``` Tag 1 Tag 2 Tag 3 Left Right **Explicit equivalents (when needed):** Code Live ```
Cluster content Cluster content
Left Right
``` Cluster content Cluster content Left Right ## Cover & Sidebar [Section titled “Cover & Sidebar”](#cover--sidebar) **Cover** - Full-viewport hero layout (min-height: 100dvh, centered content): Code Live ```

Hero

Centered full-viewport layout

``` # Hero Centered full-viewport layout **Sidebar** - Main content + sidebar (stacks on mobile, side-by-side on tablet+): Code Live ```
Main content (1fr)
``` Main content Sidebar ## Center [Section titled “Center”](#center) Centers content horizontally and vertically. Code Live ```

Centered

``` Centered **Explicit equivalent:** Code Live ```

Centered

``` Centered ## Container [Section titled “Container”](#container) Centered content wrapper with max-width and horizontal padding. Use **one class** per element. | Class | Max Width | Use Case | | ------------------ | -------------- | ------------------------------ | | `af-container` | 90em (1440px) | Default, standard page content | | `af-container-xs` | 25rem (400px) | Narrow forms, sidebars | | `af-container-sm` | 40rem (640px) | Narrow content | | `af-container-md` | 48rem (768px) | Tablet-optimized | | `af-container-lg` | 64rem (1024px) | Desktop content | | `af-container-xl` | 80rem (1280px) | Wide layouts | | `af-container-2xl` | 96rem (1536px) | Extra-wide layouts | **Tip:** Use **one class only**. `af-container-xl` is enough. Do not combine `af-container af-container-xl`. For responsive sizing, use the responsive suffix: `af-container af-container-lg@xl` (default on mobile, large at xl breakpoint). ### Basic Container [Section titled “Basic Container”](#basic-container) Code Live ```
``` Container content with default max-width (90em / 1440px) ### Container Sizes [Section titled “Container Sizes”](#container-sizes) Code Live ```
Extra small (400px max)
Small (640px max)
Medium (768px max)
Large (1024px max)
Extra large (1280px max)
``` xs - 400px max sm - 640px max md - 768px max lg - 1024px max xl - 1280px max ### Live Examples [Section titled “Live Examples”](#live-examples-2) Default container: Container content with default max-width (90em / 1440px) Container sizes: xs - 400px max sm - 640px max md - 768px max lg - 1024px max xl - 1280px max ## Surface [Section titled “Surface”](#surface) Surface pattern for creating simple containers with background, border, and border-radius. Unlike cards, surfaces don’t include padding or shadows—you add those yourself. ### Basic Surface [Section titled “Basic Surface”](#basic-surface) Code Live ```

Surface with padding added

``` Surface with padding added ### Surface Variants [Section titled “Surface Variants”](#surface-variants) Use `af-is-*` modifier classes to change the surface background: Code Live ```
Default surface (primary)
Secondary surface
Tertiary surface
``` Default surface (primary background) Secondary surface variant Tertiary surface variant ### When to Use Surface vs Card [Section titled “When to Use Surface vs Card”](#when-to-use-surface-vs-card) * **Surface** (`af-surface`): Simple container without padding or shadow. Use for panels, backgrounds, or when you need full control over spacing. * **Card** (`af-card`): Full component with padding, shadow, and semantic parts. Use for content containers with structure. ### Live Example [Section titled “Live Example”](#live-example) Default surface (primary background) Secondary surface variant Tertiary surface variant ## Section [Section titled “Section”](#section) Section pattern for consistent vertical spacing between page sections. Adds padding-block (top and bottom padding) to create visual separation. ### Basic Section [Section titled “Basic Section”](#basic-section) Code Live ```

Section Title

Section content

``` ### Section Title Section content ### Section Sizes & Variants [Section titled “Section Sizes & Variants”](#section-sizes--variants) Code Live ```
Small spacing
Default spacing
Large spacing
Hero (extra padding)
Alternate background
Narrow container
``` ### Small Section Reduced vertical spacing (space-4) ### Default Section Standard vertical spacing (space-6) ### Large Section Increased vertical spacing (space-8) ### Section Variants [Section titled “Section Variants”](#section-variants) * `af-section-hero` - Extra padding for hero sections * `af-section-alt` - Alternate background (`--af-color-surface-primary`) * `af-section-narrow` - Constrains child `.af-container` to `--af-container-max-w-md` ### Use Cases [Section titled “Use Cases”](#use-cases) * Page sections with consistent spacing * Content areas that need vertical rhythm * Separating major content blocks ### Live Example [Section titled “Live Example”](#live-example-1) ### Small Section Reduced vertical spacing (space-4) ### Default Section Standard vertical spacing (space-6) ### Large Section Increased vertical spacing (space-8) ## Spacer [Section titled “Spacer”](#spacer) Utility for adding vertical spacing (margin-block) between elements. Useful when you need spacing but don’t want to use a full stack layout. ### Basic Usage [Section titled “Basic Usage”](#basic-usage) Code Live ```
Content
Small spacer above
Content
Medium spacer above
Content
Large spacer above
``` Content Small spacer above Content Medium spacer above Content Large spacer above Content ### Spacer Sizes [Section titled “Spacer Sizes”](#spacer-sizes) * `af-spacer-sm` - Small spacing (space-2) * `af-spacer-md` - Medium spacing (space-4) * `af-spacer-lg` - Large spacing (space-6) ### When to Use [Section titled “When to Use”](#when-to-use) * Adding spacing between individual elements * Creating gaps in non-stack layouts * Quick vertical rhythm without changing layout structure **Note:** For consistent vertical layouts, prefer `af-stack` with gap utilities. Use spacer for one-off spacing needs. ### Live Example [Section titled “Live Example”](#live-example-2) Content Small spacer above Content Medium spacer above Content Large spacer above Content ## Position [Section titled “Position”](#position) Position utilities for controlling element positioning and placement. ### Position Values [Section titled “Position Values”](#position-values) Code Live ```
Relative positioning
Absolute positioning
Sticky positioning
Revert to default
``` Relative container ### Shorthand Classes [Section titled “Shorthand Classes”](#shorthand-classes) Code Live ```
Relative (shorthand)
Absolute (shorthand)
Sticky (shorthand)
``` Relative (shorthand) ### Position Offsets [Section titled “Position Offsets”](#position-offsets) Code Live ```
Top-left corner
Top-right corner
Bottom-left corner
Bottom-right corner
``` Top-left Top-right Bottom-left Bottom-right Relative container ### Available Classes [Section titled “Available Classes”](#available-classes) **Position:** * `af-pos-relative` / `af-relative` - `position: relative` * `af-pos-absolute` / `af-absolute` - `position: absolute` * `af-pos-sticky` / `af-sticky` - `position: sticky` * `af-pos-revert` - `position: revert` **Offsets:** * `af-inset-0` - `inset: 0` (all edges) * `af-top-0` - `top: 0` * `af-right-0` - `right: 0` * `af-bottom-0` - `bottom: 0` * `af-left-0` - `left: 0` ### Live Example [Section titled “Live Example”](#live-example-3) Top-left Top-right Bottom-left Bottom-right Relative container ## Responsive Suffixes [Section titled “Responsive Suffixes”](#responsive-suffixes) All layout classes support responsive variants using the `@{bp}` suffix. See [Responsive Suffix](/docs/responsive-suffix) for the full syntax and breakpoint table. Code Live ```
``` Medium gap on mobile, large gap on tablet+ Item 2 ## Flex Alignment Utilities [Section titled “Flex Alignment Utilities”](#flex-alignment-utilities) Control alignment in flex containers: ### Justify Content (Horizontal Alignment) [Section titled “Justify Content (Horizontal Alignment)”](#justify-content-horizontal-alignment) Code Live ```
Start
Center
End
Space Between
Space Around
Space Evenly
``` Start Aligned Center Aligned End Aligned Space Between ### Align Items (Vertical Alignment) [Section titled “Align Items (Vertical Alignment)”](#align-items-vertical-alignment) Code Live ```
Start
Center
End
Stretch
Baseline
``` Start Aligned Center Aligned End Aligned ### Responsive Alignment [Section titled “Responsive Alignment”](#responsive-alignment) Code Live ```
Start on mobile, center on tablet+
``` Start on mobile Center on tablet+ ### Live Example [Section titled “Live Example”](#live-example-4) Justify content examples: StartAligned CenterAligned EndAligned SpaceBetween Align items examples: StartAligned CenterAligned EndAligned ## Masonry (Experimental) [Section titled “Masonry (Experimental)”](#masonry-experimental) Masonry layout creates a waterfall-style layout where items flow into columns based on their height, similar to Pinterest-style layouts. ⚠️ **Experimental Feature** - Uses CSS Grid Lanes, which has very limited browser support. See [Browser Support](/docs/browser-support) for details. ### Browser Support [Section titled “Browser Support”](#browser-support) * ✅ **Safari Technology Preview 234+** (December 2025) - Full support * ⚠️ **Chrome 140+** - Available behind experimental flag * ⚠️ **Firefox 147+** - Available behind experimental flag * ⚠️ **Edge** - Available behind experimental flag **Fallback:** In unsupported browsers, automatically falls back to regular CSS Grid (items display in a standard grid, not masonry). ### Class Reference [Section titled “Class Reference”](#class-reference-3) | Class | Purpose | Column Width | Example | | ----------------- | ------------------- | ------------- | ------------------------------- | | `af-masonry` | Default masonry | 250px minimum | `
` | | `af-masonry-sm` | Small columns | 200px minimum | `
` | | `af-masonry-md` | Medium columns | 250px minimum | `
` | | `af-masonry-lg` | Large columns | 300px minimum | `
` | | `af-masonry-xl` | Extra large columns | 400px minimum | `
` | | `af-masonry-text` | Text-optimized | 20ch minimum | `
` | ### Basic Masonry [Section titled “Basic Masonry”](#basic-masonry) Code Live ```
Item 1
Item 2
Item 3
Item 4
``` ### Card 1 Short content ### Card 2 This card has more content to demonstrate how masonry layouts work. ### Card 3 Medium content ### Card 4 Another short card ### Masonry Variants [Section titled “Masonry Variants”](#masonry-variants) Code Live ```
Small columns (200px min)
Default columns (250px min)
Large columns (300px min)
Extra large columns (400px min)
Text-optimized (20ch min)
``` ### Card 1 Short content ### Card 2 This card has more content to demonstrate how masonry layouts work. Items flow into columns based on their height. ### Card 3 Medium content here ### Card 4 Another short card ### Live Example [Section titled “Live Example”](#live-example-5) ### Card 1 Short content ### Card 2 This card has more content to demonstrate how masonry layouts work. Items flow into columns based on their height. ### Card 3 Medium content here ### Card 4 Another short card ### Card 5 This is a longer card with more content to show how items of different heights flow into the masonry layout. The browser automatically places each item in the column that gets it closest to the top. ### Card 6 Short ### When to Use [Section titled “When to Use”](#when-to-use-1) * Photo galleries with varying image heights * Card layouts with different content lengths * Article teasers or blog post previews * Product listings with varying descriptions ### Polyfill for Production [Section titled “Polyfill for Production”](#polyfill-for-production) For production use in unsupported browsers, consider using a JavaScript polyfill: ``` // Feature detect and load polyfill if needed if (!CSS.supports('display', 'grid-lanes')) { import('masonry-layout').then(({ default: Masonry }) => { const grids = document.querySelectorAll('.af-masonry'); grids.forEach(grid => { new Masonry(grid, { itemSelector: '> *', columnWidth: 250, gutter: 16 }); }); }); } ``` See [Browser Support](/docs/browser-support#masonry-layout-grid-lanes-experimental) for more details. ## Gap Utilities [Section titled “Gap Utilities”](#gap-utilities) Control spacing between grid items or flex items: **Source of truth:** Gap utilities are defined in `grid.css` and documented in [Grid](/docs/grid). | Class | Gap Size | Token Value | Example | | ------------ | ---------------- | -------------- | -------------------------------------------- | | `af-gap-0` | No gap | `--af-space-0` | `
` | | `af-gap-xs` | Extra small | `--af-space-1` | `
` | | `af-gap-sm` | Small | `--af-space-2` | `
` | | `af-gap-lg` | Large | `--af-space-4` | `
` | | `af-gap-xl` | Extra large | `--af-space-5` | `
` | | `af-gap-2xl` | 2XL | `--af-space-6` | `
` | | `af-gap-3xl` | 3XL | `--af-space-7` | `
` | | `af-gap-4xl` | 4XL | `--af-space-8` | `
` | | (default) | Medium (default) | `--af-space-3` | `
` | **Usage:** Gap utilities can override default gaps in any layout recipe: Code Live ```
Override stack's default gap
Override inline's default gap
Override grid's default gap
``` Override stack's default gap (large) Item 2 ## Complete Class Reference [Section titled “Complete Class Reference”](#complete-class-reference) All classes available in `layouts.css`: ### Stack Classes (5) [Section titled “Stack Classes (5)”](#stack-classes-5) * `af-stack` - Default vertical stack (medium gap) * `af-stack-sm` - Small gap vertical stack * `af-stack-md` - Medium gap vertical stack (same as default) * `af-stack-lg` - Large gap vertical stack * `af-stack-xl` - Extra large gap vertical stack ### Inline Classes (5) [Section titled “Inline Classes (5)”](#inline-classes-5) * `af-inline` - Default horizontal wrap (medium gap) * `af-inline-sm` - Small gap horizontal wrap * `af-inline-md` - Medium gap horizontal wrap (same as default) * `af-inline-lg` - Large gap horizontal wrap * `af-inline-xl` - Extra large gap horizontal wrap ### Cluster / Spread / Center Classes (3) [Section titled “Cluster / Spread / Center Classes (3)”](#cluster--spread--center-classes-3) * `af-cluster` - Inline cluster (wrap + center alignment) * `af-spread` - Inline spread (space-between) * `af-center` - Center contents on both axes ### Container Classes (7) [Section titled “Container Classes (7)”](#container-classes-7) * `af-container` - Default container (90em / 1440px max-width) * `af-container-xs` - Extra small container (400px max-width) * `af-container-sm` - Small container (640px max-width) * `af-container-md` - Medium container (768px max-width) * `af-container-lg` - Large container (1024px max-width) * `af-container-xl` - Extra large container (1280px max-width) * `af-container-2xl` - 2xl container (1536px max-width) ### Gap Utilities (9) [Section titled “Gap Utilities (9)”](#gap-utilities-9) * `af-gap-0` - No gap * `af-gap-xs` - Extra small gap * `af-gap-sm` - Small gap * `af-gap-md` - Medium gap * `af-gap-lg` - Large gap * `af-gap-xl` - Extra large gap * `af-gap-2xl` / `af-gap-3xl` / `af-gap-4xl` - Larger gaps (`--af-space-6`…`8`) **Total: 29 layout classes** - All support responsive variants with `@` suffix (e.g., `af-stack@md`) **Note:** Grid classes are documented separately. See [Grid](/docs/grid) for complete grid documentation. ## Best Practices [Section titled “Best Practices”](#best-practices) * Use `af-stack` for vertical layouts * Use `af-inline` for horizontal wrapping layouts * See [Grid](/docs/grid) for grid layouts (equal columns and 12-column system) * Prefer layout recipes (`af-stack`, `af-inline`, `af-grid`, `af-container`) over many atomic utility classes * Use responsive suffixes for breakpoint-specific styles * Combine layout recipes with pattern classes for complex layouts * Use `af-justify-*` and `af-items-*` for fine-grained alignment control ## Next Steps [Section titled “Next Steps”](#next-steps) * [Grid](/docs/grid) — equal columns and the 12-column system * [Responsive Suffix](/docs/responsive-suffix) — breakpoint variants with `@` * [Recipes](/docs/recipes) — copy-paste page compositions built from these primitives # Framework Support > Using Airframe with React, Angular, Next.js, Vue, and vanilla HTML Airframe is CSS-only and framework-agnostic. Install the core package and use it with any framework or vanilla HTML. ## Install [Section titled “Install”](#install) ``` npm install @airframeui/core ``` ``` @import "@airframeui/core/core.css"; ``` ``` ``` ## React [Section titled “React”](#react) ``` /* src/index.css */ @import "@airframeui/core/core.css"; ``` ``` function App() { return (
) } ``` See [React Recipes](/docs/react-recipes) for copy-paste ready components. ## Next.js [Section titled “Next.js”](#nextjs) ### App Router [Section titled “App Router”](#app-router) ``` /* app/globals.css */ @import "@airframeui/core/core.css"; ``` ``` // app/layout.tsx import './globals.css' export default function RootLayout({ children }) { return ( {children} ) } ``` ### Pages Router [Section titled “Pages Router”](#pages-router) ``` /* styles/globals.css */ @import "@airframeui/core/core.css"; ``` ``` // pages/_app.tsx import '../styles/globals.css' export default function App({ Component, pageProps }) { return } ``` See [Next.js Setup](/docs/nextjs) for a complete guide. ## Angular [Section titled “Angular”](#angular) ``` npm install @airframeui/core ``` Add to `angular.json` under `projects..architect.build.options`: ``` "styles": [ "node_modules/@airframeui/core/core.css", "src/styles.scss" ] ``` Use directly in templates: ``` @Component({ selector: 'app-dashboard', standalone: true, template: `

Dashboard

Revenue

$84,200

` }) export class DashboardComponent {} ``` See [Angular Setup](/docs/angular) for a complete guide. ## Vue [Section titled “Vue”](#vue) ``` /* src/main.css */ @import "@airframeui/core/core.css"; ``` ``` ``` ## Vanilla HTML [Section titled “Vanilla HTML”](#vanilla-html) ``` ``` ## Next Steps [Section titled “Next Steps”](#next-steps) * [Installation](/docs/installation) - Get started * [Usage](/docs/usage) - Learn the basics * [Angular Setup](/docs/angular) - Angular specific guide * [Next.js Setup](/docs/nextjs) - Next.js specific guide * [React Recipes](/docs/react-recipes) - React examples # Badges & Chips Badges, chips, pills, icon boxes, avatars, spinners, and skeletons for status indicators and loading states. Intent badges and chips use soft backgrounds with hard text for WCAG AA contrast on small labels. ## Patterns [Section titled “Patterns”](#patterns) * **[Avatar](/docs/patterns/badges-chips/avatar)**: `af-avatar`, `af-avatar-{sm|lg}` * **[Badge](/docs/patterns/badges-chips/badge)**: `af-badge`, `af-is-*` (soft + hard) * **[Chip](/docs/patterns/badges-chips/chip)**: `af-chip`, `af-is-*` (soft + hard) * **[Icon box](/docs/patterns/badges-chips/icon-box)**: `af-icon-box`, `af-is-sm` / `af-is-lg` * **[Pill](/docs/patterns/badges-chips/pill)**: `af-pill`, `af-pill__tag`, `af-is-on-primary` * **[Skeleton](/docs/patterns/badges-chips/skeleton)**: `af-skeleton`, `af-skeleton-*` * **[Spinner](/docs/patterns/badges-chips/spinner)**: `af-spinner`, `af-spinner-{sm|lg}` # Avatar > User profile images or initials Avatars display user profile pictures or initials. ## Basic usage [Section titled “Basic usage”](#basic-usage) ```
AB
JD
CD
Alex Brown
``` ## Sizes [Section titled “Sizes”](#sizes) * `af-avatar-sm` - Small avatar * `af-avatar` - Default size * `af-avatar-lg` - Large avatar ## Live example [Section titled “Live example”](#live-example) JD AB CD ![Alex Brown](https://via.placeholder.com/40) # Badge > Small status indicators for counts, labels, or state Badges are small status indicators, typically used for counts, labels, or status. Intent variants use a **soft background** with **hard text** (`--af-color-*-soft` + `--af-color-*-hard`) so label-sized type meets WCAG AA contrast. Mid-tone intent colors are reserved for fills and accents, not badge text. ## Basic usage [Section titled “Basic usage”](#basic-usage) ``` Default Secondary Success Warning Danger Info ``` ## Live example [Section titled “Live example”](#live-example) DefaultSecondarySuccessWarningDangerInfo # Chip > Tags, filters, and removable items Chips are used for tags, filters, and removable items, with a distinct visual style from badges. Intent variants use a **soft background** with **hard text** (`--af-color-*-soft` + `--af-color-*-hard`) so small labels meet WCAG AA contrast, matching badges. ## Basic usage [Section titled “Basic usage”](#basic-usage) ``` Default Secondary Success Warning Danger Info ``` ## Live example [Section titled “Live example”](#live-example) DefaultSecondarySuccessWarningDangerInfo # Icon Box > Icon container for feature cards and badges Icon container for feature cards, section headers, and badges. Uses primary-soft background and primary color. ## Basic Usage [Section titled “Basic Usage”](#basic-usage) Code Live ``` ``` ** ## Sizes [Section titled “Sizes”](#sizes) * `af-icon-box` - Default (3rem) * `af-icon-box af-is-sm` - Small (2.5rem) * `af-icon-box af-is-lg` - Large (4rem) Code Live ``` S M L ``` ****** ## With Feature Card [Section titled “With Feature Card”](#with-feature-card) Code Live ```

Active users

Subtitle or supporting line.

``` ** ### Active users Subtitle or supporting line. # Pill > Rounded announcement or status pill, optionally an interactive link Pills are rounded, bordered badges used for announcements, promos, or standalone status callouts — typically paired with a short tag and a link. Unlike `af-badge` and `af-chip`, which are meant to sit inline with text, a pill is a self-contained unit often used as a link (e.g. “New: Feature name →”). ## Basic usage [Section titled “Basic usage”](#basic-usage) ``` New Standalone pill New Link pill ``` ## Live example [Section titled “Live example”](#live-example) New Standalone pill [New Link pill →](#) ## On primary backgrounds [Section titled “On primary backgrounds”](#on-primary-backgrounds) Add `af-is-on-primary` when placing a pill on a brand-color or gradient background (for example, a hero section). It swaps to translucent, on-primary-safe colors instead of the default surface/border tokens. ``` New Built for AI-assisted workflows ``` [New Built for AI-assisted workflows →](#) # Skeleton > Skeleton loaders for content placeholders Skeleton loaders provide visual placeholders while content is loading. ## Basic usage [Section titled “Basic usage”](#basic-usage) ```
``` ## Accessibility [Section titled “Accessibility”](#accessibility) * Mark the loading region `aria-busy="true"` while skeletons are shown * Skeletons are decorative and should be `aria-hidden="true"` ## Variants [Section titled “Variants”](#variants) * `af-skeleton-circle` - Circular skeleton (for avatars, icons) * `af-skeleton-text` - Text line skeleton ## Live example [Section titled “Live example”](#live-example) # Spinner > CSS-only loading spinner CSS-only loading spinner for indicating loading states. ## Basic usage [Section titled “Basic usage”](#basic-usage) ```
``` ## Accessibility [Section titled “Accessibility”](#accessibility) * Decorative spinners should be `aria-hidden="true"` * When a spinner stands alone, provide an accessible name (`aria-label="Loading"` or visually hidden text) ## Sizes [Section titled “Sizes”](#sizes) * `af-spinner-sm` - Small spinner * `af-spinner` - Default size * `af-spinner-lg` - Large spinner ## Live example [Section titled “Live example”](#live-example) # Buttons > Accessible button pattern with multiple variants, sizes, and states Buttons are split into individual pattern pages: ## Patterns [Section titled “Patterns”](#patterns) * **[Button](/docs/patterns/button/button)**: `af-btn`, `af-is-*`, states, sizes * **[Button Group](/docs/patterns/button/button-group)**: `af-btn-group` * **[Icon Button](/docs/patterns/button/icon-button)**: `af-btn-icon` * **[Link Button](/docs/patterns/button/link-button)**: `` # Button Group > Group related buttons together Group related buttons together: Code Live ```
``` Left Middle Right ## Live Example [Section titled “Live Example”](#live-example) LeftMiddleRight # Button > Primary button pattern with variants, sizes, and states The button pattern provides accessible, semantic buttons with consistent styling and multiple variants. ## Basic Usage [Section titled “Basic Usage”](#basic-usage) Code Live ``` ``` Primary Button ## Variants [Section titled “Variants”](#variants) Use the `af-is-*` modifier classes to change the button’s intent. `af-btn` is primary by default: * `af-is-secondary` - Secondary action (less prominent than primary) * `af-is-tertiary` - Tertiary action (least prominent) * `af-is-success` - Success/positive action * `af-is-warning` - Warning action * `af-is-danger` - Destructive action * `af-is-info` - Informational action * `af-is-outline` - Transparent background with border Code Live ``` ``` Primary Secondary Tertiary Success Warning Danger Info Outline ## Outline [Section titled “Outline”](#outline) Use `af-is-outline` to create a border-only button. It can be combined with intent classes. Code Live ``` ``` Outline Outline Secondary Outline Tertiary Outline Success Outline Warning Outline Danger ## Sizes [Section titled “Sizes”](#sizes) Buttons come in three sizes: Code Live ``` ``` Small Default Large ## Component Tokens [Section titled “Component Tokens”](#component-tokens) Buttons expose a few component tokens for easy sizing and spacing overrides: * `--af-control-min-height` (shared across controls) * `--af-btn-min-height` * `--af-btn-gap` * `--af-btn-icon-size` * `--af-btn-padding-x`, `--af-btn-padding-y`, `--af-btn-radius` Code Live ``` ``` Primary ## States [Section titled “States”](#states) ### Disabled [Section titled “Disabled”](#disabled) **For accessibility, prefer the native `disabled` attribute first** (for `
Disabled Link ``` Disabled Button Disabled Primary [Disabled Link](#) ### Loading [Section titled “Loading”](#loading) Use the loading state to indicate an action in progress. **For accessibility, prefer ARIA attributes first** (`aria-busy="true"`), with CSS classes available as a fallback (e.g., for `` tags instead of ` Loading... ``` Loading... [Loading...](#) ### Active [Section titled “Active”](#active) For toggle buttons or active states. **For accessibility, prefer ARIA attributes first** (`aria-pressed="true"` for toggles or `aria-current="page"` for navigation), with CSS classes available as a fallback (e.g., for `` tags instead of ` Current Page Active ``` Active [Current Page](#) [Active](#) ## Accessibility [Section titled “Accessibility”](#accessibility) * Uses native ` ``` ## Live Example [Section titled “Live Example”](#live-example) # Link Button > Style links as buttons Style links as buttons when they trigger actions: Code Live ``` Link as Button Primary Link Button ``` [Link as Button](#) [Primary Link Button](#) ## Live Example [Section titled “Live Example”](#live-example) [Link as Button](#) [Primary Link Button](#) # Content & Messaging Patterns for displaying content, messages, and status information. ## Patterns [Section titled “Patterns”](#patterns) * **[Alert](/docs/patterns/content/alert)**: `af-alert`, `af-is-*` * **[Banner](/docs/patterns/content/banner)**: `af-banner`, `af-is-*` * **[Callout](/docs/patterns/content/callout)**: `af-callout`, `af-is-*` * **[Card](/docs/patterns/content/card)**: `af-card`, `af-card__*` * **[Empty State](/docs/patterns/content/empty-state)**: `af-empty-state`, `af-empty-state-*` * **[KPI](/docs/patterns/content/kpi)**: `af-kpi`, `af-kpi-*` * **[Meter](/docs/patterns/content/meter)**: `` * **[Progress](/docs/patterns/content/progress)**: `` + `.af-progress` * **[Toast](/docs/patterns/content/toast)**: `af-toast`, `af-is-*` # Alert Alert messages for important information. ## Variants [Section titled “Variants”](#variants) ```
Primary Alert: This is a primary alert message.
Success Alert: Operation completed successfully.
Warning Alert: Please review this information.
Danger Alert: An error has occurred.
Info Alert: Here's some helpful information.
``` ### Variant Classes [Section titled “Variant Classes”](#variant-classes) * `af-is-primary` - Primary/informational * `af-is-success` - Success/positive * `af-is-warning` - Warning/caution * `af-is-danger` - Error/destructive * `af-is-info` - Informational ## Live Example [Section titled “Live Example”](#live-example) **Primary Alert:** This is a primary alert message. **Success Alert:** Operation completed successfully. **Warning Alert:** Please review this information. **Danger Alert:** An error has occurred. **Info Alert:** Here’s some helpful information. # Banner > Banner messages for site-wide announcements Banner messages for site-wide announcements. ## Markup [Section titled “Markup”](#markup) ```
Banner: Important site-wide message.
``` ## Live example [Section titled “Live example”](#live-example) **Banner:** Important site-wide message. # Callout > Subtle alert variant for less urgent messages Subtle alert variant for less urgent messages. ## Markup [Section titled “Markup”](#markup) ```
Primary Callout: Subtle alert variant.
Success Callout: Success message.
Info Callout: Informational message.
``` ## Live example [Section titled “Live example”](#live-example) **Primary Callout:** Subtle alert variant. **Success Callout:** Success message. **Info Callout:** Informational message. # Card Cards group related content with optional media, headers, and actions. Variants align with [Tailwind UI Cards](https://tailwindcss.com/plus/ui-blocks/application-ui/layout/cards): basic, with header/footer, gray footer/body, edge-to-edge on mobile, and well. ## Basic card [Section titled “Basic card”](#basic-card) Code Live ```

Card Title

Card body content goes here.

``` ## Card Title Card body content goes here. ## Card with header [Section titled “Card with header”](#card-with-header) Code Live ```

Card Title

Card body content goes here.

``` ## Card Title Card body content goes here. ## Card with footer [Section titled “Card with footer”](#card-with-footer) Code Live ```

Card body content goes here.

``` Card body content goes here. Save Cancel ## Card with header and footer [Section titled “Card with header and footer”](#card-with-header-and-footer) Code Live ```

Card Title

Card body content goes here.

``` ## Card Title Card body content goes here. Action ## Card with gray footer [Section titled “Card with gray footer”](#card-with-gray-footer) Add `af-is-muted` to the footer, or `af-card--footer-muted` on the card, for a muted background that extends to the card edges. Code Live ```

Card body content goes here.

``` Card body content goes here. Save Cancel ## Card with gray body [Section titled “Card with gray body”](#card-with-gray-body) Add `af-is-muted` to the body, or `af-card--body-muted` on the card, for a muted body background that extends to the card edges. Code Live ```

Card Title

Card body with muted background.

``` ## Card Title Card body with muted background. ## Card, edge-to-edge on mobile [Section titled “Card, edge-to-edge on mobile”](#card-edge-to-edge-on-mobile) Add `af-card-edge` so the card bleeds to the container edges on viewports under 48rem. Use inside a padded container; override `--af-card-edge-offset` if your container padding differs. Code Live ```

Card Title

On small screens this card extends to the edges.

``` ## Card Title On small screens this card extends to the edges. ## Well [Section titled “Well”](#well) A softer, muted card with no shadow. Use `af-well` for a simple contained block (e.g. for charts, forms, or secondary content). Code Live ```

Well Title

Softer card with muted background and no shadow.

``` ## Well Title Softer card with muted background and no shadow. ## Well, edge-to-edge on mobile [Section titled “Well, edge-to-edge on mobile”](#well-edge-to-edge-on-mobile) Add `af-well-edge` so the well bleeds to the container edges on small viewports. Code Live ```

Well that extends to the edges on mobile.

``` Well that extends to the edges on mobile. ## Card with image [Section titled “Card with image”](#card-with-image) Code Live ```
Description

Card Title

Card body content goes here.

``` ![Description](https://placehold.co/600x400) ## Card Title Card body content goes here. ## Card with overline and subtitle [Section titled “Card with overline and subtitle”](#card-with-overline-and-subtitle) Code Live ```
OPTIONAL OVERLINE

Card Title

Optional Subtitle

Card body content goes here.

``` OPTIONAL OVERLINE ## Card Title Optional Subtitle Card body content goes here. ## Card with buttons [Section titled “Card with buttons”](#card-with-buttons) Code Live ```
OPTIONAL OVERLINE

Card Title

Optional Subtitle

Card body content goes here.

``` OPTIONAL OVERLINE ## Card Title Optional Subtitle Card body content goes here. Action 1 Action 2 ## Card with links [Section titled “Card with links”](#card-with-links) Code Live ```
OPTIONAL OVERLINE

Card Title

Optional Subtitle

Card body content goes here.

``` OPTIONAL OVERLINE ## Card Title Optional Subtitle Card body content goes here. [Link 1](#) [Link 2](#) ## Full card link [Section titled “Full card link”](#full-card-link) Make the entire card clickable by using an `` tag: Code Live ```

Card Title

Entire card is clickable.

``` ## [Card Title](#) [Entire card is clickable.](#) ## Card parts [Section titled “Card parts”](#card-parts) * `af-card` – Base card container * `af-card-edge` – Edge-to-edge on mobile (inside a padded container; override `--af-card-edge-offset` if needed) * `af-card--footer-muted` – Card whose footer uses muted background (or add `af-is-muted` on the footer) * `af-card--body-muted` – Card whose body uses muted background (or add `af-is-muted` on the body) * `af-card__image` – Card image (full width, top-aligned) * `af-card__header` – Optional header section * `af-card__overline` – Small uppercase text above title * `af-card__title` – Card title/heading * `af-card__subtitle` – Subtitle text below title * `af-card__body` – Main card content (`af-is-muted` for gray body) * `af-card__footer` – Optional footer section (`af-is-muted` for gray footer) * `af-card__actions` – Container for buttons/links in footer * `af-well` – Softer card (muted background, no shadow) * `af-well-edge` – Well, edge-to-edge on mobile ## Hover effect [Section titled “Hover effect”](#hover-effect) By default, cards don’t have hover effects. Add the `af-has-hover` modifier class to enable hover shadow enhancement: Code Live ```

Card Title

Hover over this card to see the shadow effect.

``` ## Card Title Hover over this card to see the shadow effect. ## Visual style [Section titled “Visual style”](#visual-style) Cards have a subtle shadow. When the entire card is a link, it shows a focus ring for keyboard navigation. # Empty State > Empty state pattern for when there's no content to display Empty state pattern for when there’s no content to display. ## Markup [Section titled “Markup”](#markup) ```
📭

No items found

Get started by creating your first item.

``` ## Live example [Section titled “Live example”](#live-example) 📭 ### No items found Get started by creating your first item. Create Item # KPI > Key Performance Indicator displays for metrics and statistics Key Performance Indicator displays for metrics and statistics. Positive and negative change lines use `--af-color-success-hard` / `--af-color-danger-hard` so small delta text stays readable on surface backgrounds. ## Markup [Section titled “Markup”](#markup) ```
Total Users
1,234
+12%
``` ## Live example [Section titled “Live example”](#live-example) Total Users 1,234 +12% Revenue $45,678 +5% Churn Rate 2.3% -0.5% # Meter > Meter element for displaying scalar measurements Meter element for displaying scalar measurements. ## Markup [Section titled “Markup”](#markup) ``` 70% 50% 30% ``` ## Live example [Section titled “Live example”](#live-example) 70% 50% 30% # Progress > Progress bars for showing completion status Progress bars for showing completion status. ## Native `` element [Section titled “Native \ element”](#native-progress-element) ``` ``` ## Custom progress bar [Section titled “Custom progress bar”](#custom-progress-bar) ```
``` ## Live example [Section titled “Live example”](#live-example) # Toast > Toast notifications for temporary messages Toast notifications for temporary messages. ## Markup [Section titled “Markup”](#markup) ```
Success! Your changes have been saved.
``` ## Accessibility [Section titled “Accessibility”](#accessibility) * Status / success / info toasts: `role="status"` (polite live region) * Errors / urgent toasts: `role="alert"` (assertive live region) * Prefer `role="status"` by default — `role="alert"` interrupts screen readers and should be reserved for failures that need immediate attention * Decorative icons should be `aria-hidden="true"` * CSS styles the toast only; announcement behavior comes from the live-region role when the toast is inserted into the DOM ## Live example [Section titled “Live example”](#live-example) (Look in the corners of the screen!) **Success!** Your changes have been saved. # Data Display Patterns for displaying structured data and information. ## Patterns [Section titled “Patterns”](#patterns) * **[Accordion](/docs/patterns/data-display/accordion)**: `af-accordion` * **[Code Block](/docs/patterns/data-display/code-block)**: `af-code-block` * **[Description List](/docs/patterns/data-display/description-list)**: `af-dl` * **[List Group](/docs/patterns/data-display/list-group)**: `af-list-group`, `af-list-group-*` * **[Steps](/docs/patterns/data-display/steps)**: `af-steps`, `af-step`, `af-step-*` * **[Table](/docs/patterns/data-display/table)**: `af-table`, `af-table-striped` * **[Timeline](/docs/patterns/data-display/timeline)**: `af-timeline` # Accordion > Collapsible content sections using native
Collapsible content sections using native `
` element. ## Markup [Section titled “Markup”](#markup) ```
Section 1

Content for section 1 goes here.

Section 2 (Open)

This section is open by default.

``` ## Live example [Section titled “Live example”](#live-example) # Code Block > Code blocks for displaying code snippets Airframe styles `
` and `` elements directly. No class needed for basic usage. ## Inline code [Section titled “Inline code”](#inline-code) ``` 

Use npm install @airframeui/core to get started.

``` ### Preview [Section titled “Preview”](#preview) Use `npm install @airframeui/core` to get started. ## Code block [Section titled “Code block”](#code-block) Wrap code in `
` for multi-line blocks: ``` 
  function greet(name) { console.log('Hello, ' + name + '!'); } greet('World');  
``` ### Preview [Section titled “Preview”](#preview-1) ``` function greet(name) { console.log('Hello, ' + name + '!'); } greet('World'); ``` ## With language class [Section titled “With language class”](#with-language-class) Add a language class to `` for syntax highlighter compatibility: ```
  :root { --af-base-primary: #018183; --af-font-body: 'Inter', sans-serif; }  
``` ### Preview [Section titled “Preview”](#preview-2) ``` :root { --af-base-primary: #018183; --af-font-body: 'Inter', sans-serif; } ``` ## Multiple blocks [Section titled “Multiple blocks”](#multiple-blocks) ```
  npm install @airframeui/core  
  @import "@airframeui/core/core.css";  
``` ### Preview [Section titled “Preview”](#preview-3) ``` npm install @airframeui/core ``` ``` @import "@airframeui/core/core.css"; ``` ## Class reference [Section titled “Class reference”](#class-reference) | Element/Class | Purpose | | ------------------------- | ------------------------------------------------------------------- | | `
` | Styled automatically. Padding, background, border, rounded corners. | | `` (inside `
`) | Transparent background, inherits font. | | `` (inline) | Inline code with subtle background. | | `.af-code-block` | Alias for `
` styling. Not required. | ## CSS reference [Section titled “CSS reference”](#css-reference) ``` pre, .af-code-block { padding: var(--af-space-4); background: var(--af-color-surface-secondary); border: var(--af-border-width) solid var(--af-color-border); border-radius: var(--af-radius-md); overflow-x: auto; font-family: var(--af-font-code); font-size: var(--af-text-sm); line-height: var(--af-leading-normal); } pre code { background: transparent; padding: 0; } ``` ## Related [Section titled “Related”](#related) * [Typography](/docs/utilities/typography)

# Description List

> Key-value pairs for displaying structured information

Key-value pairs for displaying structured information. ## Markup [Section titled “Markup”](#markup) ``` 
Name
John Doe
Email
john@example.com
Role
Administrator
Status
Active
``` ## Live example [Section titled “Live example”](#live-example) * Name John Doe * Email * Role Administrator * Status Active # List Group > Selectable list for navigation or selection Selectable list for navigation or selection. ## Markup [Section titled “Markup”](#markup) ```
  • Item 1
  • Active Item
  • Item 3
  • Disabled Item
  • Item 5
``` ## States [Section titled “States”](#states) * `af-is-active` - Active/selected item * `af-is-disabled` - Disabled item ## Live example [Section titled “Live example”](#live-example) * Item 1 * Active Item * Item 3 * Disabled Item * Item 5 # Steps > Progress tracker for multi-step processes Progress tracker for multi-step processes. ## Markup [Section titled “Markup”](#markup) ```
1
Step 1
2
Step 2
3
Step 3
4
Step 4
``` ## States [Section titled “States”](#states) * `af-is-complete` - Completed step * `af-is-active` - Current/active step * (no modifier) - Upcoming step ## Live example [Section titled “Live example”](#live-example) 1 Step 1 2 Step 2 3 Step 3 4 Step 4 # Table > Tables for displaying tabular data Tables for displaying tabular data. ## Basic table [Section titled “Basic table”](#basic-table) ```
Name Email Role
John Doe john@example.com Admin
``` ## Striped table [Section titled “Striped table”](#striped-table) ```
``` ## Live example [Section titled “Live example”](#live-example) | Name | Email | Role | | ----------- | ------------------ | ----- | | John Doe | | Admin | | Jane Smith | | User | | Bob Johnson | | User | | Product | Price | Stock | | ------- | ----- | ----- | | Item 1 | $10 | 50 | | Item 2 | $20 | 30 | | Item 3 | $30 | 20 | # Timeline > Timeline pattern for displaying chronological events Timeline pattern for displaying chronological events. ## Markup [Section titled “Markup”](#markup) ```
Event 1
Description of event 1
Event 2
Description of event 2
``` ## Live example [Section titled “Live example”](#live-example) Event 1 Description of event 1 Event 2 Description of event 2 Event 3 Description of event 3 # Forms Complete form patterns for building accessible, user-friendly forms. ## Patterns [Section titled “Patterns”](#patterns) * **[Checkbox](/docs/patterns/forms/checkbox)**: `af-checkbox` * **[Classless form](/docs/patterns/forms/classless-form)**: `form.af-form` * **[Field](/docs/patterns/forms/field)**: `af-field`, `af-field__*` * **[File input](/docs/patterns/forms/file-input)**: `af-file-input` * **[Form layout](/docs/patterns/forms/form-layout)**: `af-field-inline`, `
` * **[Input](/docs/patterns/forms/input)**: `af-input`, states, tokens * **[Input group](/docs/patterns/forms/input-group)**: `af-input-group`, `af-input-group-addon` * **[Label](/docs/patterns/forms/label)**: semantic labels (optional `.af-label`) * **[Radio](/docs/patterns/forms/radio)**: `af-radio` * **[Range](/docs/patterns/forms/range)**: `af-range` * **[Select](/docs/patterns/forms/select)**: `af-select` (or `form.af-form`) * **[Switch](/docs/patterns/forms/switch)**: `role="switch"` (or `.af-switch`) * **[Textarea](/docs/patterns/forms/textarea)**: `af-textarea`, `af-is-auto-grow` * **[Validation & error states](/docs/patterns/forms/validation)**: `aria-invalid`, `af-is-error`, `aria-describedby` # Checkbox > Checkboxes for selecting one or more options Checkboxes for selecting one or more options. Labels automatically use flex layout when they contain checkboxes. Control size uses `--af-choice-size` (default `1.5rem`, shared with radio and the switch track height). Override it to scale all choice controls together — see [Tokens](/docs/tokens#shared-control-tokens). ## Markup [Section titled “Markup”](#markup) ``` ``` ## Classless checkbox [Section titled “Classless checkbox”](#classless-checkbox) Checkboxes also work without classes inside `form.af-form`: ```
``` ## Live example [Section titled “Live example”](#live-example) \[x]Checked\[ ]UncheckedDisabled # Classless Form > Automatic styling with form.af-form For a classless approach, wrap your form in `form.af-form`. This enables automatic styling for additional form elements. ## Markup [Section titled “Markup”](#markup) ```
``` ## What works without classes [Section titled “What works without classes”](#what-works-without-classes) Inside `form.af-form`, these elements work without classes: * `input[type="text"]`, `input[type="email"]`, `input[type="password"]`, etc. * `textarea` * `input[type="checkbox"]` * `input[type="radio"]` * `input[type="range"]` * `input[type="file"]` Note: `label` and `input[type="checkbox"][role="switch"]` already work without `form.af-form` (they have default styling). `select` requires either `.af-form` wrapper or `.af-select` class. ## Live example [Section titled “Live example”](#live-example) EmailCountryChoose a countryMessageSubmit # Field > Consistent form field structure with label, control, help, and error The field pattern provides a consistent structure for form fields with labels, controls, help text, and error messages. ## Basic field [Section titled “Basic field”](#basic-field) ```
Help text goes here
``` ## Field with error [Section titled “Field with error”](#field-with-error) **Required for accessibility:** Error messages must be linked to the input via `aria-describedby`. The input references the error message’s `id` attribute. ```
Error message
``` ## Live example [Section titled “Live example”](#live-example) Label Enter text Help text goes here With Error Error message # File Input > File upload input styling File upload input. ## Markup [Section titled “Markup”](#markup) ``` ``` ## Live example [Section titled “Live example”](#live-example) # Form Layout > Inline fields and fieldset patterns ## Inline fields [Section titled “Inline fields”](#inline-fields) Fields with labels on the same line as the input. ```
``` ## Fieldset [Section titled “Fieldset”](#fieldset) Group related fields together. ```
Fieldset Example
``` ## Live example [Section titled “Live example”](#live-example) Inline Field Fieldset Example Field 1 Field 2 # Input Group > Input with prefix/suffix addons Input with prefix or suffix addons for icons, symbols, or text. ## Prefix and suffix [Section titled “Prefix and suffix”](#prefix-and-suffix) ```
$ .00
``` ## Prefix only [Section titled “Prefix only”](#prefix-only) ```
@
``` ## Suffix only [Section titled “Suffix only”](#suffix-only) ```
🔍
``` ## Live example [Section titled “Live example”](#live-example) $Amount.00 @Username Search🔍 # Input > Text inputs for single-line text entry Text inputs for single-line text entry. Supports all standard HTML input types. ## Input types [Section titled “Input types”](#input-types) ``` ``` ## States [Section titled “States”](#states) ``` ``` ## Autosize input (experimental) [Section titled “Autosize input (experimental)”](#autosize-input-experimental) Use `af-is-autosize` to let single-line inputs grow with content: ``` ``` **Info:** Inputs growing horizontally as you type can cause layout shifts (bad in modern UI/UX). Use autosize only for narrow, controlled cases (like tag inputs or inline search). ## Component tokens [Section titled “Component tokens”](#component-tokens) Form controls use shared control tokens plus input-specific tokens (applies to inputs, selects, and textareas): * `--af-control-min-height`, `--af-control-radius` * `--af-input-min-height`, `--af-input-font-size`, `--af-input-leading` * `--af-input-placeholder-color`, `--af-input-padding-x`, `--af-input-padding-y` ``` ``` ## Error handling [Section titled “Error handling”](#error-handling) **Required for accessibility:** When showing errors, you must: 1. Set `aria-invalid="true"` on the input 2. Link the error message via `aria-describedby` (input references error message `id`) ```
Please enter a valid email address
``` ## Live example [Section titled “Live example”](#live-example) Text input[Email input]()••••••••••••••SearchError state # Label > Styled form labels (semantic-first) Labels are automatically styled with proper typography and spacing. ## Markup [Section titled “Markup”](#markup) ``` ``` # Radio > Radio buttons for selecting a single option Radio buttons for selecting a single option from a group. Labels automatically use flex layout when they contain radios. Control size uses `--af-choice-size` (default `1.5rem`, shared with checkbox and the switch track height). Override it to scale all choice controls together — see [Tokens](/docs/tokens#shared-control-tokens). ## Markup [Section titled “Markup”](#markup) ``` ``` ## Classless radio [Section titled “Classless radio”](#classless-radio) Radios also work without classes inside `form.af-form`: ```
``` ## Live example [Section titled “Live example”](#live-example) \[x]Option 1\[ ]Option 2Disabled # Range > Range slider for selecting a value within a range Range slider for selecting a value within a range. ## Markup [Section titled “Markup”](#markup) ``` ``` ## Live example [Section titled “Live example”](#live-example) 5075 # Select > Dropdown select for choosing from a list of options Dropdown select for choosing from a list of options. Select elements require either a `.af-form` wrapper or the `.af-select` class. In browsers that support [customizable `
``` ## States [Section titled “States”](#states) ``` ``` ## Option groups [Section titled “Option groups”](#option-groups) ``` ``` ## Live example [Section titled “Live example”](#live-example) Choose an optionChoose a petError stateDisabled # Switch > Toggle switch for on/off states Toggle switch for on/off states. Supports both semantic HTML and class-based approaches. Track height uses `--af-switch-height` (defaults to `--af-choice-size`, `1.5rem`). Width is `height × (1 + --af-switch-width-ratio)` (ratio default `0.8`). Checkbox and radio use the same `--af-choice-size` so the three stay visually aligned — see [Tokens](/docs/tokens#shared-control-tokens). ## Semantic switch (recommended) [Section titled “Semantic switch (recommended)”](#semantic-switch-recommended) Use `role="switch"` for better accessibility and semantic HTML. Labels automatically use flex layout when they contain switches: ``` ``` ## Class-based switch (legacy) [Section titled “Class-based switch (legacy)”](#class-based-switch-legacy) The traditional class-based approach is still supported: ``` ``` ## States [Section titled “States”](#states) ``` ``` ## Live example [Section titled “Live example”](#live-example) #### Semantic switch (recommended) \[x]Enable notifications\[ ]Dark modeDisabled option #### Class-based switch (legacy) \[x]\[ ] ## Sizing tokens [Section titled “Sizing tokens”](#sizing-tokens) ``` :root { --af-choice-size: 1.5rem; /* checkbox, radio, default switch height */ --af-switch-height: var(--af-choice-size); --af-switch-width-ratio: 0.8; } ``` # Textarea > Multi-line text input with optional auto-grow Multi-line text input for longer content. ## Basic textarea [Section titled “Basic textarea”](#basic-textarea) ``` ``` ## With rows [Section titled “With rows”](#with-rows) ``` ``` ## Auto-grow textarea [Section titled “Auto-grow textarea”](#auto-grow-textarea) Textareas can automatically grow with content using the `af-is-auto-grow` class. This uses the modern CSS `field-sizing: content` property (supported in Chrome 123+ and Edge 123+). ``` ``` **Browser Support:** The CSS `field-sizing: content` property is supported in Chrome 123+ and Edge 123+. For full browser support, install and import the polyfills package: ``` npm install @airframeui/polyfills ``` ``` // In your entry file import '@airframeui/polyfills'; ``` The polyfills automatically detect browser support and only apply JavaScript fallbacks when needed. See the [Browser Support](/docs/browser-support) documentation for framework-specific examples and our browser support philosophy. ## States [Section titled “States”](#states) ``` ``` ## Live example [Section titled “Live example”](#live-example) # Validation & Error States > Error handling, required fields, and help text ## Error handling [Section titled “Error handling”](#error-handling) Use `aria-invalid="true"` or the `af-is-error` class to indicate validation errors: ```
Please enter a valid email address
``` ## Required fields [Section titled “Required fields”](#required-fields) Indicate required fields clearly: ```
``` ## Help text [Section titled “Help text”](#help-text) Provide helpful guidance to users: ```
Must be at least 8 characters with a mix of letters and numbers
``` ## Live example [Section titled “Live example”](#live-example) Email \* Please enter a valid email address Password Must be at least 8 characters with a mix of letters and numbers ## Accessibility [Section titled “Accessibility”](#accessibility) ### Best practices [Section titled “Best practices”](#best-practices) * **Always use `
``` ### CSS classes [Section titled “CSS classes”](#css-classes) * `.af-nav-collapse` - Container for collapsible navigation * `.af-nav-collapse-open` - Show menu (alternative to removing `hidden`) ### Required ARIA [Section titled “Required ARIA”](#required-aria) * `aria-expanded` on trigger button (true/false) * `aria-controls` linking trigger to menu * `hidden` attribute to show/hide menu ### Features you must implement [Section titled “Features you must implement”](#features-you-must-implement) * Focus trapping when menu is open * Escape key to close * Return focus to trigger on close * Outside click to close (optional) # Navbar > Main navigation bar for site-wide navigation Main navigation bar for site-wide navigation. ## Markup [Section titled “Markup”](#markup) ``` ``` ## Live example [Section titled “Live example”](#live-example) [Brand](#) * [Home](#) * [About](#) * [Contact](#) # Pagination > Pagination controls for navigating through pages of content Pagination controls for navigating through pages of content. ## Markup [Section titled “Markup”](#markup) ``` ``` ## Live example [Section titled “Live example”](#live-example) * [Previous](#) * [1](#) * [2](#) * [3](#) * [Next](#) # Side Navigation > Side navigation menu for hierarchical navigation Side navigation menu for hierarchical navigation. ## Markup [Section titled “Markup”](#markup) ``` ``` ## Live example [Section titled “Live example”](#live-example) * [Active Item](#) * [Item 2](#) * [Item 3](#) # Table of Contents > Styled table of contents navigation pattern Use the `af-toc` pattern to style **in-page navigation** (e.g. “On this page” lists, long-form docs, multi-section pages). ## Markup (recommended) [Section titled “Markup (recommended)”](#markup-recommended) Use semantic HTML: * `nav` with `aria-label` * an optional heading (`h2`/`h3`) for the TOC title * `ol`/`ul` for the list Code Live ``` ``` ## Contents 1. [Introduction](#introduction) 2. [Getting started](#getting-started) 3. [Components](#components) 1. [Buttons](#buttons) 2. [Forms](#forms) 4. [Conclusion](#conclusion) ## Active link state [Section titled “Active link state”](#active-link-state) If you can set `aria-current="page"` on the active anchor, the TOC will highlight it. Code Live ``` ``` ## Contents 1. [Introduction](#intro) 2. [Usage](#usage) ## Automatic styling (no class) [Section titled “Automatic styling (no class)”](#automatic-styling-no-class) The pattern also styles semantic TOCs without the class when the nav’s label suggests “contents”: Code Live ``` ``` ## Contents 1. [Section A](#a) 2. [Section B](#b) ## Notes [Section titled “Notes”](#notes) * If you’re using the docs site, Starlight’s built-in TOC uses `nav[aria-label="Table of contents"]`, which this pattern can style without extra markup changes. * You can nest lists (`ol > li > ol`) for hierarchical pages. # Overlays Overlay patterns for modal dialogs, backdrops, and drawers. ## Patterns [Section titled “Patterns”](#patterns) * **[Backdrop](/docs/patterns/overlays/backdrop)**: `af-backdrop` * **[Dialog](/docs/patterns/overlays/dialog)**: `af-dialog`, `af-dialog-*` * **[Drawer](/docs/patterns/overlays/drawer)**: `af-drawer`, `af-drawer-*` # Backdrop > Full-screen overlay backdrop Full-screen semi-transparent overlay. Useful for custom overlay scenarios outside of native ``. **Tip:** If you’re using `` with `showModal()`, you don’t need this class. The native `::backdrop` pseudo-element is styled automatically by Airframe. ## Usage [Section titled “Usage”](#usage) ```
``` ## When to use [Section titled “When to use”](#when-to-use) * Custom modal implementations that don’t use `` * Overlay behind popovers, menus, or custom drawers * Loading overlays For standard modals and drawers, use the [Dialog](/docs/patterns/overlays/dialog) or [Drawer](/docs/patterns/overlays/drawer) patterns instead. They use native `` which handles the backdrop automatically. ## Preview [Section titled “Preview”](#preview) Content behind the backdrop Content above backdrop ## CSS reference [Section titled “CSS reference”](#css-reference) ``` .af-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(2px); z-index: 999; } ``` ## Related [Section titled “Related”](#related) * [Dialog](/docs/patterns/overlays/dialog) * [Drawer](/docs/patterns/overlays/drawer) # Dialog > Modal dialogs using the native HTML dialog element Modal dialog using the **native HTML `` element**. No JavaScript dependencies required. ## Basic dialog [Section titled “Basic dialog”](#basic-dialog) ```

Confirm action

Are you sure you want to continue? This action cannot be undone.

``` ## Preview [Section titled “Preview”](#preview) ## Why native ``? [Section titled “Why native \?”](#why-native-dialog) * **`showModal()`** marks the rest of the page as inert. * **ESC key** closes the dialog automatically. * **Body scroll lock** while the modal is open. * **`::backdrop`** pseudo-element. No extra markup for the overlay. **Note:** Native `` provides basic focus containment via page inertness, but focus trapping and focus restoration are not fully reliable across all browsers and screen readers. For production apps, supplement with a focus trap library (e.g. `focus-trap`). ## API [Section titled “API”](#api) Open with `showModal()`. Close with `close()`. ``` const dialog = document.getElementById('my-dialog'); dialog.showModal(); dialog.close(); if (dialog.open) {/* dialog is visible */} ``` ## Parts [Section titled “Parts”](#parts) | Class | Purpose | | ------------------ | ----------------------------------- | | `af-dialog` | The `` element itself | | `af-dialog-header` | Header row. Flexbox, space-between. | | `af-dialog-title` | Title text inside the header | | `af-dialog-body` | Main content area | | `af-dialog-footer` | Footer row. Flexbox, end-aligned. | ## Dialog with form [Section titled “Dialog with form”](#dialog-with-form) ```

Edit profile

``` Using `
` lets any submit button close the dialog automatically. ## Closing on backdrop click [Section titled “Closing on backdrop click”](#closing-on-backdrop-click) The native `` doesn’t close on backdrop click by default. Add this if you want it: ``` dialog.addEventListener('click', (e) => { if (e.target === dialog) dialog.close(); }); ``` ## Accessibility [Section titled “Accessibility”](#accessibility) * Use `` element. Not a `
` with `role="dialog"`. * Provide a visible title via `af-dialog-title`. * Add `aria-label` or `aria-labelledby` if the title is not visible. * Close buttons need `aria-label="Close"`. ## Related [Section titled “Related”](#related) * [Drawer](/docs/patterns/overlays/drawer) * [Backdrop](/docs/patterns/overlays/backdrop) # Drawer > Side drawer panel using native dialog Side panel using the **native HTML `` element**. Slides in from the left or right. ## Basic drawer [Section titled “Basic drawer”](#basic-drawer) ```

Navigation

``` ## Preview [Section titled “Preview”](#preview) ### Navigation × * [Dashboard](#) * [Settings](#) * [Account](#) ## Right-side drawer [Section titled “Right-side drawer”](#right-side-drawer) Add `af-drawer-right` to open from the right edge: ```

Filters

``` ## API [Section titled “API”](#api) Same as dialog. Open with `showModal()`, close with `close()`. ``` const drawer = document.getElementById('my-drawer'); drawer.showModal(); drawer.close(); ``` ## Parts [Section titled “Parts”](#parts) | Class | Purpose | | ------------------ | ------------------------------------------------------- | | `af-drawer` | The `` element. Opens from the left by default. | | `af-drawer-right` | Modifier. Opens from the right instead. | | `af-drawer-header` | Header row with title and close button | | `af-drawer-body` | Scrollable content area | ## Closing on backdrop click [Section titled “Closing on backdrop click”](#closing-on-backdrop-click) ``` drawer.addEventListener('click', (e) => { if (e.target === drawer) drawer.close(); }); ``` ## Accessibility [Section titled “Accessibility”](#accessibility) Same accessibility model as dialog. Native `` with `showModal()` marks the page as inert and provides ESC key and body scroll lock. Focus trapping and focus restoration require supplemental JS for full cross-browser reliability. ## Related [Section titled “Related”](#related) * [Dialog](/docs/patterns/overlays/dialog) * [Backdrop](/docs/patterns/overlays/backdrop) # Patterns Overview > Complete list of all CSS patterns available in Airframe Airframe includes **70+ CSS patterns** organized into 8 categories. This page provides a quick reference to all available patterns. ## Foundations [Section titled “Foundations”](#foundations) Base styling patterns for content and layout primitives. * **[Divider](/docs/patterns/foundations/divider)** - Styled `
` element * **[Images](/docs/patterns/foundations/images)** - Responsive images and figure defaults * **[Links](/docs/patterns/foundations/links)** - Link defaults * **[Lists](/docs/patterns/foundations/lists)** - List defaults and `.af-list` * **[Section & Surface](/docs/patterns/foundations/section-surface)** - Structural containers for spacing and backgrounds * **[Typography](/docs/utilities/typography)** - Semantic headings, text roles, blockquote ## Buttons, Badges & Status [Section titled “Buttons, Badges & Status”](#buttons-badges--status) Interactive elements for user actions and status indicators. * **[Button](/docs/patterns/button/button)** - Primary button pattern with variants and states * **[Button Group](/docs/patterns/button/button-group)** - Grouped buttons with connected styling * **[Icon Button](/docs/patterns/button/icon-button)** - Icon-only buttons * **[Link Button](/docs/patterns/button/link-button)** - Links styled as buttons * **[Avatar](/docs/patterns/badges-chips/avatar)** - User profile images * **[Badge](/docs/patterns/badges-chips/badge)** - Small status indicators * **[Chip](/docs/patterns/badges-chips/chip)** - Tags, filters, and removable items * **[Icon Box](/docs/patterns/badges-chips/icon-box)** - Icon container for feature cards * **[Pill](/docs/patterns/badges-chips/pill)** - Compact labeled chips for tags and meta * **[Skeleton](/docs/patterns/badges-chips/skeleton)** - Content placeholders * **[Spinner](/docs/patterns/badges-chips/spinner)** - Loading indicators ## Forms [Section titled “Forms”](#forms) Complete form patterns for building accessible, user-friendly forms. * **[Checkbox](/docs/patterns/forms/checkbox)** - Checkbox inputs * **[Classless Form](/docs/patterns/forms/classless-form)** - Automatic styling with `form.af-form` * **[Field](/docs/patterns/forms/field)** - Form field structure with labels and help text * **[File Input](/docs/patterns/forms/file-input)** - File upload inputs * **[Form Layout](/docs/patterns/forms/form-layout)** - Form structure and spacing * **[Input](/docs/patterns/forms/input)** - Text inputs (text, email, password, etc.) * **[Input Group](/docs/patterns/forms/input-group)** - Grouped form controls * **[Label](/docs/patterns/forms/label)** - Styled labels (semantic-first) * **[Radio](/docs/patterns/forms/radio)** - Radio button groups * **[Range](/docs/patterns/forms/range)** - Slider inputs * **[Select](/docs/patterns/forms/select)** - Dropdown selects * **[Switch](/docs/patterns/forms/switch)** - Toggle switches * **[Textarea](/docs/patterns/forms/textarea)** - Multi-line text inputs * **[Validation & Error States](/docs/patterns/forms/validation)** - Errors, help text, required fields ## Navigation [Section titled “Navigation”](#navigation) Navigation patterns for site navigation, tabs, breadcrumbs, and pagination. * **[Breadcrumbs](/docs/patterns/navigation/breadcrumbs)** - Breadcrumb navigation * **[Dropdown Menu](/docs/patterns/navigation/dropdown-menu)** - Dropdown menus * **[Menu List](/docs/patterns/navigation/menu-list)** - Menu and list navigation * **[Nav Collapse](/docs/patterns/navigation/nav-collapse)** - Collapsible navigation sections * **[Navbar](/docs/patterns/navigation/navbar)** - Main navigation bar * **[Pagination](/docs/patterns/navigation/pagination)** - Page navigation controls * **[Side Navigation](/docs/patterns/navigation/side-navigation)** - Sidebar navigation * **[Table of Contents](/docs/patterns/navigation/table-of-contents)** - In-page navigation for long-form content ## Content & Messaging [Section titled “Content & Messaging”](#content--messaging) Patterns for displaying content, messages, and status information. * **[Alert](/docs/patterns/content/alert)** - Alert messages * **[Banner](/docs/patterns/content/banner)** - Site-wide banner messages * **[Callout](/docs/patterns/content/callout)** - Subtle alert variant * **[Card](/docs/patterns/content/card)** - Card layouts and variants * **[Empty State](/docs/patterns/content/empty-state)** - Empty state displays * **[KPI](/docs/patterns/content/kpi)** - Key Performance Indicator displays * **[Meter](/docs/patterns/content/meter)** - Meter elements for measurements * **[Progress](/docs/patterns/content/progress)** - Progress bars * **[Toast](/docs/patterns/content/toast)** - Toast notifications ## Data Display [Section titled “Data Display”](#data-display) Patterns for displaying structured data and information. * **[Accordion](/docs/patterns/data-display/accordion)** - Collapsible content sections * **[Code Block](/docs/patterns/data-display/code-block)** - Code snippet displays * **[Description List](/docs/patterns/data-display/description-list)** - Key-value pairs * **[List Group](/docs/patterns/data-display/list-group)** - Selectable list items * **[Steps](/docs/patterns/data-display/steps)** - Multi-step progress trackers * **[Table](/docs/patterns/data-display/table)** - Tables for tabular data * **[Timeline](/docs/patterns/data-display/timeline)** - Chronological event displays ## Overlays [Section titled “Overlays”](#overlays) Overlay patterns for modal dialogs, backdrops, and drawers. * **[Backdrop](/docs/patterns/overlays/backdrop)** - Full-screen overlay backdrop * **[Dialog](/docs/patterns/overlays/dialog)** - Modal dialogs using native `` element * **[Drawer](/docs/patterns/overlays/drawer)** - Side drawer panels ## Media & Misc [Section titled “Media & Misc”](#media--misc) Utility patterns and helpers. * **[Print Styles](/docs/patterns/misc/print-styles)** - Print-specific styles and utilities * **[Tooltip](/docs/patterns/misc/tooltip)** - CSS-only tooltips ## Quick Links [Section titled “Quick Links”](#quick-links) Browse detailed documentation for each category: * [Badges & Chips](/docs/patterns/badges-chips) - Status indicators and tags * [Buttons](/docs/patterns/button) - Button patterns and variants * [Content & Messaging](/docs/patterns/content) - Cards, alerts, callouts, and more * [Data Display](/docs/patterns/data-display) - Tables, lists, and data components * [Forms](/docs/patterns/forms) - Complete form patterns * [Foundations](/docs/patterns/foundations) - Typography, lists, images, links, dividers * [Misc](/docs/patterns/misc) - Tooltips, print styles, and utilities * [Navigation](/docs/patterns/navigation) - Navigation components * [Overlays](/docs/patterns/overlays) - Dialogs, drawers, and modals ## Getting Started [Section titled “Getting Started”](#getting-started) All patterns are available when you import the core CSS: ``` @import "@airframeui/core/core.css"; ``` Each pattern uses semantic class names with the `af-` prefix. For example: * `af-btn` for buttons * `af-card` for cards * `af-input` for inputs * `af-table` for tables See the [Usage](/docs/usage) guide for more information on getting started with Airframe patterns. # Accessibility ## WCAG 2.2 A/AA Compliance Promise [Section titled “WCAG 2.2 A/AA Compliance Promise”](#wcag-22-aaa-compliance-promise) **Airframe is built to meet WCAG 2.2 Level A & AA for default styles and Airframe patterns when used as documented.** Final compliance depends on product content and implementation choices (copy, structure, alt text, validation messaging, etc.). ## Built-In Accessibility [Section titled “Built-In Accessibility”](#built-in-accessibility) Airframe follows a **semantic-first, CSS-only where possible** approach that prevents common accessibility failures. ### Semantic-First Defaults [Section titled “Semantic-First Defaults”](#semantic-first-defaults) Airframe ships base styles that assume semantic HTML: * Headings are headings (`h1`-`h6`) * Buttons are `
` }) export class UserTableComponent { users = input<{ id: number; name: string; email: string; role: string }[]>([]); } ``` ## Theming [Section titled “Theming”](#theming) ### Custom tokens [Section titled “Custom tokens”](#custom-tokens) Override tokens in your `styles.scss`. No rebuild needed. ``` /* src/styles.scss */ @import "@airframeui/core/core.css"; :root { --af-base-primary: #0066cc; --af-font-body: 'Inter', sans-serif; --af-radius-md: 0.5rem; } ``` ### Dark mode [Section titled “Dark mode”](#dark-mode) Dark mode follows system preference by default. Override per-element or globally: ```
Dark card on a light page
``` Available themes: `light`, `dark`, `high-contrast-light`, `high-contrast-dark` ### Dynamic theme switching [Section titled “Dynamic theme switching”](#dynamic-theme-switching) ``` @Component({ selector: 'app-theme-toggle', standalone: true, template: ` ` }) export class ThemeToggleComponent { isDark = false; toggleTheme(): void { this.isDark = !this.isDark; document.documentElement.setAttribute( 'data-theme', this.isDark ? 'dark' : 'light' ); } } ``` ## View Encapsulation [Section titled “View Encapsulation”](#view-encapsulation) Airframe classes work with Angular’s default view encapsulation. If you need to style Airframe elements from a parent component, use `:host` or set encapsulation to `None`: ``` @Component({ selector: 'app-custom', standalone: true, encapsulation: ViewEncapsulation.None, styles: ` .my-custom-card { --af-card-padding: var(--af-space-6); --af-card-radius: var(--af-radius-lg); } `, template: `

Custom Card

` }) export class CustomComponent {} ``` ## SSR (Angular Universal) [Section titled “SSR (Angular Universal)”](#ssr-angular-universal) Airframe CSS works with Angular SSR out of the box. No special configuration needed. The CSS is loaded via `angular.json` styles array, which works in both client and server builds. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### CSS not loading [Section titled “CSS not loading”](#css-not-loading) * Check that `@airframeui/core/core.css` is in the `styles` array in `angular.json` * Or check that `src/styles.scss` imports it and is itself in the `styles` array ### Styles not applying [Section titled “Styles not applying”](#styles-not-applying) 1. Use `class` not `className` (Angular uses `class`) 2. Check that no conflicting CSS is overriding Airframe styles 3. If view encapsulation is blocking styles, override tokens via CSS variables instead of targeting Airframe class internals ### Build errors [Section titled “Build errors”](#build-errors) * Angular 17+ required * Node 20+ required by the Angular CLI toolchain (Airframe CSS itself has no Node runtime requirement) * Run `npm install` to ensure `@airframeui/core` is installed ## Next Steps [Section titled “Next Steps”](#next-steps) * [Patterns](/docs/patterns/button) - See all available patterns * [Tokens](/docs/tokens) - Customise your theme * [Layouts](/docs/layouts) - Structural primitives * [Accessibility](/docs/accessibility) - Built-in accessibility # Grid CSS Grid layout for creating responsive grids with equal-width columns or asymmetric layouts. ## Grid [Section titled “Grid”](#grid) ### Class Reference [Section titled “Class Reference”](#class-reference) | Class | Purpose | Columns | Example | | ------------ | --------------------------------- | ------------------ | -------------------------- | | `af-grid` | Auto-adjusting grid (recommended) | Auto-fit (default) | `
` | | `af-grid-1` | 1 equal column (explicit) | 1 | `
` | | `af-grid-2` | 2 equal columns (explicit) | 2 | `
` | | `af-grid-3` | 3 equal columns (explicit) | 3 | `
` | | `af-grid-4` | 4 equal columns (explicit) | 4 | `
` | | `af-grid-5` | 5 equal columns (explicit) | 5 | `
` | | `af-grid-6` | 6 equal columns (explicit) | 6 | `
` | | `af-grid-7` | 7 equal columns (explicit) | 7 | `
` | | `af-grid-8` | 8 equal columns (explicit) | 8 | `
` | | `af-grid-9` | 9 equal columns (explicit) | 9 | `
` | | `af-grid-10` | 10 equal columns (explicit) | 10 | `
` | | `af-grid-11` | 11 equal columns (explicit) | 11 | `
` | | `af-grid-12` | 12 equal columns (explicit) | 12 | `
` | ### Equal Columns [Section titled “Equal Columns”](#equal-columns) For equal-width columns, use `af-grid-1` through `af-grid-12`: ```
Item 1
Item 2
Item 1
Item 2
Item 3
``` ### Responsive Grid [Section titled “Responsive Grid”](#responsive-grid) All grid classes support responsive variants. Use responsive suffixes for breakpoint-specific columns: ```
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 1
Item 2
Item 3
Item 4
``` **Available responsive variants:** All `af-grid-1` through `af-grid-12` support `@xs`, `@sm`, `@md`, `@lg`, `@xl`, and `@2xl` suffixes. Use `af-grid` as the default auto-fit grid. **Tip:** New to the `@{bp}` syntax? See [Responsive Suffix](/docs/responsive-suffix) for breakpoints, patterns, and best practices. ### Gap Override [Section titled “Gap Override”](#gap-override) Use `af-gap-sm`, `af-gap-lg`, etc. to override the default `gap-md`: ```
Large gap between columns
Extra large gap
``` **Note:** `af-grid-1` through `af-grid-12` are standalone classes that include `display: grid` and `gap-md` automatically. You don’t need to combine them with `af-grid`. ### Live Examples [Section titled “Live Examples”](#live-examples) Auto-adjusting: 2 children = 2 columns 50% 50% Auto-adjusting: 3 children = 3 columns 33% 33% 33% Explicit: 6 columns 1 2 3 4 5 6 ## 12-Column Grid [Section titled “12-Column Grid”](#12-column-grid) For asymmetric layouts, use `af-grid` with `af-col-span-*` classes. ### Class Reference [Section titled “Class Reference”](#class-reference-1) | Class | Purpose | Usage | | ---------------------------------------- | ------------------- | ------------------------------ | | `af-col-span-1` through `af-col-span-12` | Column spans (1-12) | Use inside `af-grid` container | ### Basic 12-Column Grid [Section titled “Basic 12-Column Grid”](#basic-12-column-grid) ```
Main content (8/12)
Sidebar (4/12)
``` **Mobile-first default:** Items in a 12-column grid automatically default to full width (12 columns) on mobile. You only need to specify responsive spans for larger screens. ### Mobile-First Pattern [Section titled “Mobile-First Pattern”](#mobile-first-pattern) The pattern `af-col-span-8@lg` means: * **Mobile (default):** Full width (12 columns) - automatic * **Large screens and up:** 8 columns (two-thirds width) **Note:** The base `af-col-span-12` class exists for completeness but isn’t needed - full width is the automatic default. However, responsive variants like `af-col-span-12@md` are available if you need to explicitly set full width at a specific breakpoint (e.g., `af-col-span-6 af-col-span-12@md` for “half width on mobile, full width on medium+”). ### Column Spans Reference [Section titled “Column Spans Reference”](#column-spans-reference) | Class | Spans | Example | Use Case | | ---------------- | ----------------------- | ------------------------------ | ------------------------------------------------ | | `af-col-span-1` | 1 column | `
` | Narrow column | | `af-col-span-2` | 2 columns | `
` | Small column | | `af-col-span-3` | 3 columns | `
` | Quarter width | | `af-col-span-4` | 4 columns | `
` | One-third width | | `af-col-span-5` | 5 columns | `
` | Custom width | | `af-col-span-6` | 6 columns (half width) | `
` | Half width | | `af-col-span-7` | 7 columns | `
` | Custom width | | `af-col-span-8` | 8 columns (two-thirds) | `
` | Two-thirds width | | `af-col-span-9` | 9 columns | `
` | Three-quarters width | | `af-col-span-10` | 10 columns | `
` | Custom width | | `af-col-span-11` | 11 columns | `
` | Custom width | | `af-col-span-12` | 12 columns (full width) | `
` | **Full width (exists but not needed - default)** | **Note:** Full width (12 columns) is the default - no class needed. The `af-col-span-12` class exists for completeness but isn’t recommended. For explicit full width at breakpoints, use responsive variants: `af-col-span-12@md`, `af-col-span-12@lg`, etc. **Responsive:** All spans support responsive suffixes: `af-col-span-6@md`, `af-col-span-8@lg`, `af-col-span-12@md`, etc. Items default to full width on mobile, so you only need responsive classes for larger screens. ### Live Example (12-Column) [Section titled “Live Example (12-Column)”](#live-example-12-column) Main content (8 columns on large screens) Sidebar (4 columns on large screens) # Next.js Setup Guide Airframe works seamlessly with Next.js in both App Router and Pages Router. ## Quick Start [Section titled “Quick Start”](#quick-start) ### 1. Install [Section titled “1. Install”](#1-install) ``` npm install @airframeui/core # or pnpm add @airframeui/core ``` ### 2. Import CSS [Section titled “2. Import CSS”](#2-import-css) #### App Router (app directory) [Section titled “App Router (app directory)”](#app-router-app-directory) Create or update `app/globals.css`: ``` @import "@airframeui/core/core.css"; ``` Then import it in `app/layout.tsx`: ``` import './globals.css' export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( {children} ) } ``` #### Pages Router (pages directory) [Section titled “Pages Router (pages directory)”](#pages-router-pages-directory) Create or update `styles/globals.css`: ``` @import "@airframeui/core/core.css"; ``` Then import it in `pages/_app.tsx`: ``` import '../styles/globals.css' import type { AppProps } from 'next/app' export default function App({ Component, pageProps }: AppProps) { return } ``` ### 3. Use Patterns [Section titled “3. Use Patterns”](#3-use-patterns) Now you can use Airframe classes anywhere: ``` // app/page.tsx (App Router) or pages/index.tsx (Pages Router) export default function Home() { return (

Welcome

) } ``` ## App Router Examples [Section titled “App Router Examples”](#app-router-examples) ### Basic Page [Section titled “Basic Page”](#basic-page) ``` // app/dashboard/page.tsx export default function Dashboard() { return (

Dashboard

Main Content

Content goes here

Sidebar

Sidebar content

) } ``` ### Server Component with Forms [Section titled “Server Component with Forms”](#server-component-with-forms) ``` // app/contact/page.tsx export default function Contact() { return (