Platform
← Foundations

FOUNDATIONS FEATURE

The sx-* / ui-* grammar

Declarative UI composition with two attribute namespaces: sx-* for layout and spacing, ui-* for primitive identity, resolved from the active skin's tokens.

Live demo

Revenue

Quarter-to-date, all regions — composed entirely from attributes.

On track Review Surface, radius and tone all come from the skin.
sx-* layout grammar ui-* primitive grammar 9 domains / 43 slices Per-route CSS bundles LLM-friendly composition

The sx-* / ui-* grammar

Semitexa UI composes interfaces with an attribute-based CSS grammar instead of bespoke class names. There are two namespaces:

  • sx-* — layout and composition, applicable to any element.
  • ui-* — primitive identity and its modifiers, used with primitives.

The grammar is deliberately small and regular, which makes it both readable for a human and easy for a language model to emit correctly. The CSS that each attribute resolves to is the stable contract; the Twig macros are optional developer convenience.

Nine domains

v1 ships 9 attributes across 43 slices. The vocabulary is intentionally finite:

Attribute Domain Values
sx-layout Layout stack (flex column) · cluster (flex row wrap, centered) · grid (auto-fit minmax) · frame (block)
sx-gap Spacing 0 1 2 3 4 6 8 — a non-linear rem scale (0.25rem … 2rem)
sx-padding Spacing same scale as sx-gap
sx-radius Radius none · sm · md · lg · pill
sx-surface Surface flat · panel (panel bg + subtle border) · raised (+ shadow)
sx-tone Tone neutral · brand · success · warning · danger
sx-align Alignment start · center · end · stretch
sx-justify Alignment start · center · end · between
ui-text Text role body · muted · title · label

Every value that touches colour, surface, or radius resolves through the active skin's --ui-* tokens — sx-surface="panel" reads --ui-surface-panel and --ui-border-subtle, so the same markup re-skins itself when the skin changes (see Token-driven UI).

Composition example

A panel that stacks a header row above its body, with the header spread between a title and an action, reads like its own description:

twig
<section sx-layout="stack" sx-gap="4" sx-surface="panel" sx-padding="4" sx-radius="lg">    <header sx-layout="cluster" sx-justify="between" sx-align="center">        <h2 ui-text="title">Revenue</h2>        <button ui="button" ui-tone="brand">Export</button>    </header>    <p ui-text="muted">Quarter-to-date, all regions.</p></section>

sx-layout="stack" makes the section a vertical flex column with a 1rem gap; the panel surface, 1rem padding, and lg radius come straight from skin tokens; the header is a centered cluster justified between so the title and the button sit at opposite ends. There is not a single bespoke class or colour literal in the markup — and the preview on this page is exactly this kind of composition.

ui-* and the primitives

While sx-* arranges any element, ui-* carries primitive identity and modifiers. ui="button" declares a button primitive; ui-variant, ui-tone, and ui-size modify it; ui="field-shell" with ui-state="invalid" cascades danger styling to a descendant label, input, and error text. The primitives and the grammar are two halves of the same idea: identity and modifiers in attributes, resolution in tokens. (See Primitives & tokens for the primitive vocabulary.)

Per-route CSS, compiled from usage

Because the grammar is a fixed vocabulary, Semitexa can scan a template, see exactly which slices it uses, and compile a per-route CSS bundle containing only those slices — typically under 3KB gzipped. platform-ui:css:inspect <template> reports the slices a template uses and the resulting bundle size; platform-ui:css:explain sx-gap:4 shows the CSS a single slice emits and the tokens it references. You never ship CSS for slices a page does not use.

Why it matters

A small, regular grammar is the difference between composition that a person (or a model) can write fluently and a sprawl of one-off class names that only their author understands. The vocabulary stays finite by design — sx-shadow, sx-density, sx-border, responsive switches and explicit grid column counts are deliberately deferred to v1.1+ rather than bloating the v1 surface. Declarative composition, token-resolved styling, and usage-compiled CSS are one coherent story: you describe structure in attributes, and the active skin decides what it looks like.

© Edsger W. Dijkstra:"Simplicity is prerequisite for reliability."

grammar.md — composition exampleImplementation slice
<section sx-layout="stack" sx-gap="4" sx-surface="panel" sx-padding="4" sx-radius="lg">    <header sx-layout="cluster" sx-justify="between" sx-align="center">        <h2 ui-text="title">Revenue</h2>        <button ui="button" ui-tone="brand">Export</button>    </header>    <p ui-text="muted">Quarter-to-date, all regions.</p></section>

How it works

v1 ships 9 attributes across 43 slices. Every value that touches colour, surface or radius resolves through the active skin's --ui-* tokens, so sx-surface="panel" reads --ui-surface-panel and re-skins itself when the skin changes. Because the grammar is a fixed vocabulary, the CSS compiler scans a template, sees exactly which slices it uses, and emits a per-route bundle of only those slices — typically under 3KB gzipped.

Why it matters

A small, regular grammar is the difference between composition a person or a model can write fluently and a sprawl of one-off class names. The vocabulary stays finite by design (sx-shadow, sx-density, responsive switches are deferred to v1.1+). You describe structure in attributes; the active skin decides what it looks like; the page only ships CSS for slices it actually uses.