Layout (Container, Stack, Flex, Grid, Divider)
import { Container, Divider, Flex, Grid, Stack } from '@absoluteui/components/layout';import '@absoluteui/components/layout/style.css';Using Angular? See Layout (Container, Stack, Flex, Grid, Divider) for Angular.
What it does
Section titled “What it does”Layout primitives: Container, Stack, Flex (and Inline), Grid, and Divider. The CSS classes are the primary API and work without JavaScript. The JS helpers (Stack.apply, Flex.apply, Grid.apply, Container.apply, Divider.create) give frameworks and AI assistants a validated, typed API. They apply the same classes and custom properties to an element you own. Each returns a handle whose destroy() removes exactly what it added.
When to use
Section titled “When to use”- Spacing siblings with token gaps instead of ad-hoc margins.
- Responsive card or tile grids that reflow without media queries (aui-grid–auto).
- Centering page content with a token maximum width (aui-container).
- Separating groups of content with a semantic or decorative divider.
When not to use
Section titled “When not to use”- Visual grouping with a border or background: use Surface or Card.
- Tabular data: use a table (Data Table in a later release).
- Reordering content visually so it differs from the reading order (flex row-reverse on meaningful sequences).
Examples
Section titled “Examples”Vertical stack with a token gap
Section titled “Vertical stack with a token gap”import { Stack } from '@absoluteui/components/layout';
const list = document.createElement('div');document.body.append(list);const stack = Stack.apply(list, { gap: 6 });stack.update({ align: 'start' });Responsive auto-fit grid
Section titled “Responsive auto-fit grid”import { Container, Grid } from '@absoluteui/components/layout';
const page = document.createElement('main');const tiles = document.createElement('div');page.append(tiles);document.body.append(page);Container.apply(page, { size: 'xl' });const grid = Grid.apply(tiles, { minColumnWidth: '14rem', gap: 4 });// Later, when the view is removed:grid.destroy();Wrapping row with a vertical divider
Section titled “Wrapping row with a vertical divider”import { Divider, Flex } from '@absoluteui/components/layout';import { Button } from '@absoluteui/components/button';
const toolbar = document.createElement('div');const save = document.createElement('button');save.textContent = 'Save';Button.enhance(save);const share = document.createElement('button');share.textContent = 'Share';Button.enhance(share);toolbar.append(save, Divider.create({ orientation: 'vertical' }), share);document.body.append(toolbar);Flex.apply(toolbar, { gap: 2, align: 'center', justify: 'end' });Labelled divider between sign-in options
Section titled “Labelled divider between sign-in options”import { Divider } from '@absoluteui/components/layout';
document.body.append(Divider.create({ label: 'or' }));Change the default gap globally
Section titled “Change the default gap globally”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { layout: { defaultGap: 3 } } });import { Divider, Flex, Stack } from '@absoluteui/components/layout';import '@absoluteui/components/layout/style.css';
const panel = document.querySelector<HTMLElement>('#settings');const actions = document.querySelector<HTMLElement>('#settings-actions');if (panel && actions) { const stack = Stack.apply(panel, { gap: 6 }); panel.insertBefore(Divider.create(), actions); Flex.apply(actions, { gap: 2, justify: 'end' }); window.addEventListener('pagehide', () => { stack.destroy(); });}More usage
Section titled “More usage”<main class="aui-container aui-container--md"> <div class="aui-stack aui-gap-6"> <div class="aui-grid aui-grid--auto aui-gap-4">...tiles...</div> <hr class="aui-divider"> <div class="aui-inline aui-gap-2 aui-justify-end">...buttons...</div> </div></main>import { Grid } from '@absoluteui/components/layout';
const tiles = document.querySelector<HTMLElement>('#tiles');if (tiles) Grid.apply(tiles, { minColumnWidth: '14rem', gap: 4 });Anatomy
Section titled “Anatomy”<main class="aui-container aui-container--lg"> centered, max-inline-size, inline padding <div class="aui-stack aui-gap-6"> flex column + gap <div class="aui-flex aui-gap-2 aui-justify-between"> wrapping row ... <div class="aui-divider aui-divider--vertical" role="separator" aria-orientation="vertical"> ... </div> <hr class="aui-divider"> semantic horizontal separator <div class="aui-divider aui-divider--labelled" role="separator" aria-label="or"> <span class="aui-divider__label">or</span> </div> <div class="aui-grid aui-grid--auto" style="--aui-grid-min: 14rem"> (custom property set via the CSSOM) <div>tile</div> ... </div> </div></main>API reference
Section titled “API reference”Factory
Section titled “Factory”Stack.apply(el: HTMLElement, options?: StackOptions): LayoutHandle<StackOptions>; Flex.apply(el: HTMLElement, options?: FlexOptions): LayoutHandle<FlexOptions>; Grid.apply(el: HTMLElement, options?: GridOptions): LayoutHandle<GridOptions>; Container.apply(el: HTMLElement, options?: ContainerOptions): LayoutHandle<ContainerOptions>; Divider.create(options?: DividerOptions, doc?: Document): HTMLElementGlobal configuration key: layout (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
gap |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 |
Stack, Flex, Grid: gap step mapped to the space-N token. Defaults to the configured defaultGap. | |
align |
'start' | 'center' | 'end' | 'stretch' | 'baseline' |
Stack, Flex: cross-axis alignment (aui-align-*). | |
justify |
'start' | 'center' | 'end' | 'between' | 'around' | 'evenly' |
Flex: main-axis distribution (aui-justify-*). | |
wrap |
boolean |
true |
Flex: wrap items onto new lines (false adds aui-flex–nowrap). |
direction |
'row' | 'row-reverse' |
"row" |
Flex: row follows the writing direction; row-reverse adds aui-flex–reverse. |
columns |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto' |
"auto" |
Grid: fixed column count or responsive auto-fit mode. |
minColumnWidth |
string |
"16rem" |
Grid auto mode: minimum column width as a strict CSS length (for example ‘12rem’); sets –aui-grid-min. |
size |
'sm' | 'md' | 'lg' | 'xl' |
"lg" |
Container: maximum inline size from container-width-* tokens. |
orientation |
'horizontal' | 'vertical' |
"horizontal" |
Divider: <hr> when horizontal, role=separator with aria-orientation when vertical. |
label |
string |
Divider: short centered text; also the separator’s accessible name. Horizontal only. | |
decorative |
boolean |
false |
Divider: hide from assistive technology. Cannot be combined with label. |
defaultGap |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 |
4 |
Gap applied by Stack, Flex, and Grid helpers when gap is omitted. Globally configurable. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
element |
HTMLElement |
LayoutHandle: the consumer element the helper applies to. |
options |
Readonly<O> |
LayoutHandle: current options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<O>): void |
Merge, validate, and apply options. Invalid options throw and leave the element unchanged. |
destroy(): void |
Remove the classes and custom properties this helper added, restore displaced classes and custom property values, and unsubscribe. Idempotent. |
isCssLength(value: unknown): value is string |
The strict CSS length check used for minColumnWidth. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-container |
Centered, width-capped region with space-4 inline padding (default width container-width-lg). |
aui-container--sm | --md | --lg | --xl |
Container maximum inline size. |
aui-stack |
Flex column with a gap (default space-4). |
aui-flex |
Flex row that wraps, with a gap (default space-4). |
aui-inline |
Like aui-flex with align-items: center, for inline clusters such as tags or buttons. |
aui-flex--nowrap | aui-flex--reverse |
Flex modifiers. |
aui-grid |
CSS grid with a gap (default space-4). |
aui-grid--cols-1 ... aui-grid--cols-12 |
Fixed equal-width columns. |
aui-grid--auto |
Responsive auto-fit columns of at least var(–aui-grid-min, 16rem), never wider than the container. |
aui-gap-0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 |
Gap utilities mapped to space-N tokens. |
aui-align-start | center | end | stretch | baseline |
align-items utilities. |
aui-justify-start | center | end | between | around | evenly |
justify-content utilities. |
aui-divider |
Horizontal separator line (<hr> or role=separator). |
aui-divider--vertical |
Vertical separator line; stretches to the row height. |
aui-divider--labelled | aui-divider__label |
Horizontal divider with centered text. |
--aui-grid-min |
Custom property: minimum column width in auto mode (default 16rem). |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-text-muted | --aui-container-width-lg | --aui-container-width-md | --aui-container-width-sm | --aui-container-width-xl | --aui-font-family-sans | --aui-font-size-sm | --aui-line-height-tight | --aui-space-1 | --aui-space-10 | --aui-space-12 | --aui-space-2 | --aui-space-3 | --aui-space-4 | --aui-space-5 | --aui-space-6 | --aui-space-8
TypeScript definitions
Section titled “TypeScript definitions”type LayoutGap = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12;type LayoutAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';type LayoutJustify = 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';type GridColumns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';interface StackOptions { gap?: LayoutGap; align?: LayoutAlign }interface FlexOptions { gap?: LayoutGap; align?: LayoutAlign; justify?: LayoutJustify; wrap?: boolean; direction?: 'row' | 'row-reverse' }interface GridOptions { columns?: GridColumns; minColumnWidth?: string; gap?: LayoutGap }interface ContainerOptions { size?: 'sm' | 'md' | 'lg' | 'xl' }interface DividerOptions { orientation?: 'horizontal' | 'vertical'; label?: string; decorative?: boolean }interface LayoutHandle<O> { readonly element: HTMLElement; readonly options: Readonly<O>; update(options: Partial<O>): void; destroy(): void }Accessibility
Section titled “Accessibility”Pattern: Presentational CSS layout (no ARIA widget pattern). Dividers follow HTML <hr> and the WAI-ARIA separator role (non-focusable).
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Not applicable: layout primitives and dividers are not focusable. Focus follows the source order of the consumer’s content, including under aui-flex–reverse. |
| Element | Role |
|---|---|
| container, stack, flex, grid | none added (the consumer element keeps its own semantics) |
| horizontal divider | separator (native <hr>) |
| vertical or labelled divider | separator (role attribute on a <div>) |
| decorative divider | hidden (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-orientation |
vertical divider | “vertical” |
aria-label |
labelled divider | The label text (separator children are presentational) |
aria-hidden |
decorative divider | “true” |
Not focusable. Layout never changes the DOM order, so reading and focus order stay in source order.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 1.3.2 Meaningful Sequence | A | |
| 1.4.10 Reflow | AA | |
| 1.4.12 Text Spacing | AA |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Auto-fit grids and wrapping flex rows support 320 CSS px reflow (WCAG 1.4.10).
- Gaps use rem-based tokens, so spacing scales with user text-size and text-spacing settings.
- Row-reverse only changes visual order; avoid it where order carries meaning (WCAG 1.3.2).
- Screen readers differ in whether they announce separators and their labels; labelled dividers are supplementary, not structural.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”Applied and destroyed. The primitives have no interactive states.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| - | X.apply(el, options) |
applied (classes added) |
| applied | update(options) |
applied with new classes; the previous modifiers are removed |
| applied | global defaultGap change |
gap class updated (when gap is omitted) |
| applied | destroy() |
element restored to its previous classes and custom properties |
Accessibility notes
Section titled “Accessibility notes”- Auto-fit grids and wrapping rows support 320 CSS px reflow (WCAG 1.4.10). Fixed column counts do not collapse; prefer
columns: 'auto'for content grids. - Gaps are rem-based, so they scale with user text size and text-spacing overrides.
row-reversechanges only the visual order. Avoid it when order carries meaning (WCAG 1.3.2).- Screen readers differ in how they announce separators. Do not rely on a divider for structure; use headings or landmarks.
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”aui-grid--auto uses repeat(auto-fit, minmax(min(var(--aui-grid-min, 16rem), 100%), 1fr)): columns are at least the minimum width but never wider than the container. Flex rows wrap by default. Containers keep inline padding at every width.
Right-to-left
Section titled “Right-to-left”Logical properties throughout (max-inline-size, margin-inline, padding-inline, border-inline-start). Flex rows follow the writing direction, so start/end and row order mirror automatically.
Theming
Section titled “Theming”Spacing uses space-* tokens (identical across built-in themes). Divider lines use color-border and labels color-text-muted. In forced-colors mode, divider lines are drawn in CanvasText.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { layout: { defaultGap: 3 } } });Existing handles that omit gap update immediately.
Component configuration
Section titled “Component configuration”An explicit gap option overrides defaultGap. All options are dynamic through update(). CSS-only usage defaults to space-4, which matches the default defaultGap.
None. Layout primitives render no icons.
Security
Section titled “Security”Helpers only change classList and set one custom property (--aui-grid-min) through el.style.setProperty. They never set a style attribute or parse HTML. minColumnWidth must match a strict CSS length pattern: a non-negative number with a known unit, or 0. This rejects calc(), var(), and declaration injection such as '10rem; color: red'. Divider labels use textContent. CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry.
Performance
Section titled “Performance”Constant work per apply()/update(): a few classList operations and at most one custom property. No DOM listeners; one configuration subscription per handle (released by destroy()). There is no dedicated performance budget yet.
Supported data scale
Section titled “Supported data scale”Not data-driven. Grids and stacks hold any number of children; layout cost is the browser’s.
Edge cases
Section titled “Edge cases”- Applying Stack, Flex, or Grid to an element that already has one of them throws
LAYOUT_ALREADY_APPLIED. Container can be combined with any of them. - Classes that were on the element before
apply()are never removed ondestroy(). A conflicting pre-existing modifier (for exampleaui-gap-2whengap: 6is applied) is removed while applied and restored ondestroy(). - A
--aui-grid-minvalue set by the consumer beforeGrid.applyis restored ondestroy(). minColumnWidthwith a fixedcolumnscount throws, because it would be ignored.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
LAYOUT_OPTIONS |
configuration | Invalid gap, alignment, justify, wrap, direction, columns, length, size, orientation, or divider label combination. |
LAYOUT_ALREADY_APPLIED |
configuration | A display helper (Stack, Flex, Grid) or Container already owns the element. |
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION |
configuration | Invalid global layout configuration. |
Failed apply() calls leave the element unchanged.
Known limitations
Section titled “Known limitations”- Fixed grid column counts do not collapse at narrow widths.
- Labelled dividers are horizontal only.
- CSS-only usage does not follow
defaultGap; it usesspace-4unless a gap class is set. - Manual screen-reader verification of separators is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- Arbitrary gap values (only the documented
space-*steps). calc(),var(), or other CSS functions asminColumnWidth.- Masonry and subgrid layouts.