registry:ui · Layout · alpha
prototype-flex — the standardized flex row
The layout family, alpha track: the design studio's property panel edits these exact props. Every value is a native CSS token passed through 1:1 (no vocabulary mapping layer), styling is inline-style only — zero Tailwind, zero theme tokens, zero dependencies — so the item renders in any host. Single root + rest spread: the stamp mechanism's family precondition, proven here first.
$npx jixoai-ui add prototype-flex
https://ui.jixoai.com/r/prototype-flex.json
overview
Overview
Three laws define the alpha lane: single root + rest spread, zero translation, inline style only — and the eight axes forward without opinion.
SINGLE ROOT + REST SPREAD — the whole component is one div; the
consumer's attributes spread first and the family's stamps land after (replace, never
merge): data-jx-prototype-flex, data-density and the dark class. This is the
stamp mechanism's family precondition, proven here first — a studio edit or a consumer
testid lands on the same node the layout styles.
ZERO TRANSLATION — direction, wrap, align and justify ARE the CSS Box Alignment tokens, passed through verbatim (measured live in the rig below: every control's change lands in the container's computed style byte-identical). There is no "between" → "space-between" mapping layer to learn or fight; the one type coercion is gap number → px (a bare number is not a CSS length). INLINE STYLE ONLY — no Tailwind, no theme tokens, no css file: the alpha lane's reason to exist apart from utility-first Tier-1 is that it installs and renders in any host. The dispatch expectation that gap might ride the space tokens is deliberately FALSE here — the family law is zero tokens.
The eight axes are FORWARDERS, not opinions — the first-time contract declares all no-own, and the family paints nothing for them: the carriers join the consumer style attr (measured), density stamps its rung for descendants that read the kernel channels, theme rides the .dark bridge, and size echoes on the root so em-inheriting children reflow. One accessibility truth to hold: direction="row-reverse" and "column-reverse" flip the VISUAL order against the DOM order — screen readers follow the DOM, so reserve the reversed rungs for genuinely reversed contexts.
The layout trio, cross-referenced: prototype-flex — the row prototype-grid — the tracks prototype-waterfall — the columns — one contract, three engines.
prototype-flex · the rig
The property panel, live: every control below binds a real prop 1:1 — measured end-to-end in task 35, each change lands in the container's computed style (flex-direction / flex-wrap / align-items / justify-content / gap). The controls live in the stage body by design: the canvas mounts its playground snippet lazily (the collapsible dock), so anything that must stay driveable belongs beside the specimen, not in the snippet.
- direction
- wrap
- align
- justify
- gap (px)
<PrototypeFlex
direction="row"
wrap="nowrap"
align="stretch"
justify="space-between"
gap={12}
>
<span>alpha</span><span>beta</span><span>gamma</span>
</PrototypeFlex>law
The alpha contract
Three laws make the primitive studio-editable and host-agnostic — they are also why this family deliberately has no tokens.
1 · SINGLE ROOT + REST SPREAD — one div, consumer attributes first, family stamps after; the studio's edits and the layout's stamps can never fight over separate nodes. 2 · ZERO TRANSLATION — the props are the CSS: no alias vocabulary, no mapping layer to drift; the property panel edits CSS truth. 3 · INLINE STYLE ONLY — no utility classes and no theme tokens, so the item renders identically in any host and the gap value you pass is the gap that renders (there are no space tokens to inherit or collide with).
types
Types — the justify ladder, rendered
The control inventory rendered: all six justify-content union members on identical rows (three fixed-width chips, 1px frames, gap 12). align and wrap ride the rig above.
prototype-flex · justify ladder
<PrototypeFlex gap={12} align="center">
<span>first</span>
<span>second</span>
<span>third</span>
</PrototypeFlex>
<!-- every prop is a native CSS token, passed through 1:1 -->
<PrototypeFlex direction="column" justify="space-between" wrap="wrap" gap="0.75rem" />usage
Usage
One element, five optional props — omitted props inject no declaration; the CSS initial value serves.
<PrototypeFlex gap={12} align="center">
<span>first</span>
<span>second</span>
<span>third</span>
</PrototypeFlex>
<!-- every prop is a native CSS token, passed through 1:1 -->
<PrototypeFlex direction="column" justify="space-between" wrap="wrap" gap="0.75rem" />api
API
Props map to CSS 1:1 — the one type coercion: gap number → px. Everything else rides through as native div attributes.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
| direction | 'row' | 'row-reverse' | 'column' | 'column-reverse' | — | flex-direction, verbatim. Omitted → no declaration (the CSS initial: row). |
| wrap | 'nowrap' | 'wrap' | 'wrap-reverse' | — | flex-wrap, verbatim. |
| align | 'start' | 'center' | 'end' | 'stretch' | 'baseline' | — | align-items, verbatim (logical-axis Box Alignment spellings). |
| justify | 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly' | — | justify-content, verbatim. |
| gap | number | string | — | gap: number → px, string verbatim (the one type coercion). |
| class | string | — | Passed through verbatim — the component owns no class of its own. |
| ...rest | HTMLAttributes<HTMLDivElement> | spread | Every other attribute lands on the single root (stamped data-jx-prototype-flex after the spread — replace, never merge). |
Universal props
| Property | Type | Default | Description |
|---|---|---|---|
| size | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | the base scale — root font-size; parts size in em |
| shape | 'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto' | 'auto' · ambient scope | corner geometry (CSS corner-shape; §14 degrade table) |
| radius | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | corner size; auto = the concentric broadcast (§3) |
| density | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | spacing/leading scale over the kernel channels (§4) |
| color | 'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string | 'auto' · ambient scope | the hue axis of the fixed oklch primary system (§5) |
| theme | 'light' | 'dark' | 'system' | 'auto' | 'auto' · ambient scope | light/dark profile; system = the JS-mutable global (§6) |
| elevation | 'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number | 'auto' · ambient scope | official M3 levels over the surface ladder (§7) |
| motion | 'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number | 'auto' · ambient scope | intensity across the motion kernels (§8) |
axes
The eight axes on prototype-flex
The zero-translation posture extends to paint: the first-time contract is ALL NO-OWN, and the family paints nothing for any axis — carriers join the consumer style attr, density stamps its rung for descendants, theme rides the .dark bridge, size echoes on the root. Every row below is a forwarder, measured by stamp receipts rather than paint (there is no family paint to measure).
| Property | Type | Default | Description |
|---|---|---|---|
| density | '2xs' | 'xs' | 'sm' | 'default' | 'lg' | 'auto' | number (+ the five legacy spellings) | 'auto' | FORWARDER — the resolved rung stamps data-density on the flex root (measured data-density=lg with an explicit lane; null ambient), opening the kernel channels for DESCENDANTS that read them; the flex layout itself consumes none. Number unit: coefficient. |
| size | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' | FORWARDER, ECHO MEASURED — the §11 stamp lands inline on the root as font-size: var(--jx-size-effective, 1rem) (the carrier chain, measured in the style attr), so em-inheriting children reflow around it; the flex geometry (direction/wrap/gap) is untouched. Number unit: px. |
| shape | 'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto' | 'auto' | FORWARDER — the carrier joins the style attr; zero family readers (the alpha lane paints nothing). Number unit: none. |
| radius | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' | FORWARDER — carrier stamp only; zero family readers. Number unit: px. |
| color | 'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string | 'auto' | FORWARDER — carrier stamp only; children re-tint through the ambient chain if they read it. Zero family readers. Number unit: hue degrees. |
| theme | 'light' | 'dark' | 'system' | 'auto' | 'auto' | FORWARDER — dark rides the .dark class bridge on the flex root (class:dark measured with theme="dark"), re-scoping the token chains for the subtree; the layout itself is theme-blind. No number lane. |
| elevation | 'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number | 'auto' | FORWARDER — carrier stamp only; zero family readers. Number unit: dp. |
| motion | 'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number | 'auto' | FORWARDER — carrier stamp only; the layout has no transitions of its own (grep receipt: zero transition declarations in the family). Number unit: coefficient. |
Receipts: the rig's five controls each measured end-to-end (select/number change → computed flex-direction / flex-wrap / align-items / justify-content / gap update on the container, task 35); the density rung stamp (data-density=lg explicit, null ambient), the size echo (font-size 18px inline at size=18) and the dark class bridge were measured on this page's served DOM; the zero-reader rows carry grep receipts over ui/prototype-flex/ (an inline-style-only family — no css file, no tokens). The query() seat below rides the md viewport key (48rem) through the gap number→px coercion.
<script lang="ts">
import PrototypeFlex from '@ui/prototype-flex.svelte';
import { query } from '@lib/universal-props-query.svelte';
</script>
<!-- below 48rem the base (13px root) applies; at 48rem+ the md case
(18px) wins — the §11 stamp scales the root, children reflow -->
<PrototypeFlex size={query({ md: 18 }, 13)} gap={12}>…</PrototypeFlex>prototype-flex · query()
Media keys are min-width: below 48rem the base (13px root) applies; at 48rem and wider the md case wins (18px) — the §11 stamp scales the root and em-inheriting children reflow. The number lane goes bare. Note the boundary this exposes: the AXES accept query() (they are lanes), the LAYOUT props (gap, direction…) do not — they are native CSS passthroughs, number | string only. Resize across 48rem.
<script lang="ts">
import PrototypeFlex from '@ui/prototype-flex.svelte';
import { query } from '@lib/universal-props-query.svelte';
</script>
<!-- below 48rem the base (13px root) applies; at 48rem+ the md case
(18px) wins — the §11 stamp scales the root, children reflow -->
<PrototypeFlex size={query({ md: 18 }, 13)} gap={12}>…</PrototypeFlex>PrototypeFlex · universal props
<PrototypeFlex size={18} density="small">…</PrototypeFlex>a11y
Accessibility
A layout primitive: no role, no keys, no announcements of its own — its a11y story is ORDER and what consumers land on the root.
Keyboard
| Key | Action |
|---|---|
| — | Not a focus stop and no keys of its own — a plain div wrapper |
ARIA
| Attribute | Value | Description |
|---|---|---|
| visual vs DOM order | the row-reverse trade | direction="row-reverse" / "column-reverse" flip the VISUAL order against the DOM order — screen readers follow the DOM (WCAG 1.3.2: meaningful sequence); reserve the reversed rungs for genuinely reversed reading contexts. |
| rest-spread ARIA | verbatim | aria-label, role, data-* — anything in the rest lane lands on the single root after the spread, so consumer semantics compose with the layout stamps. |
| role | none authored | The container is a plain div; give it a role only when its children need grouping semantics (e.g. role="list" with role="listitem" children). |
| theme / density stamps | subtree-scoped | The .dark bridge and data-density rung re-scope token chains for descendants — visible only to children that read them. |