Dual Architecture — CSS Overview

Proof of concept. This page demonstrates the dual-architecture POC (page chrome uses --dual-* variables). iris-core will adopt this dual-output model additively under the iris namespace — no separate dual namespace ships. See research/README.md.

Single SCSS source compiles to both shadow-DOM web components and light-DOM SUIT CSS classes. Three-layer tokens (reference → semantic → component). All page chrome uses --dual-* variables.

§1 — Stats and Performance

96 KB
dist/preset/full.css
334
--dual-* vars (count-once)
14
components (+2 groups)
84
type variations
64
utility classes
5
theme modes
40 KB
dist/components.js

§2 — CSS Delivery Model

Click any node to highlight downstream delivery. SCSS source → build tools → compiled CSS / web components → consumer page.

Single SCSS source compiles two outputs via $namespace: .Dual-Button (light DOM CSS classes) and .Button (shadow-scoped web components). Tokens flow reference → semantic → component through both paths identically.

§3 — Token Architecture and Color Examples

LayerExampleRole
Reference$dual-teal-500, $dual-navy-900Raw palette primitives (SCSS only, never emitted)
Semantic--dual-action-fill-1, --dual-base-1Meaning-based tokens, emitted as CSS custom properties
Component--dual-button-fill, --dual-card-borderPer-component tokens defaulting from semantic layer

Live token swatches

--dual-base-1
--dual-base-2
--dual-text-1
--dual-text-2
--dual-action-fill-1
--dual-action-content-1
--dual-status-success
--dual-status-danger

Tokens compile from SCSS $primitives → semantic SCSS map → emitted CSS custom properties. Component vars default from semantic and can be overridden per-instance.

§4 — Components (Shadow DOM vs Light DOM)

Both paths use the same token contract. CSS var overrides work identically on both.

Button

Shadow DOM (<dual-button>)

Primary Ghost Text Danger

Light DOM (.Dual-Button)

Text Field

Shadow DOM (<dual-text-field>)

Light DOM (.Dual-TextField)

Alert (status variants)

InfoInformational message.
SuccessOperation completed.
WarningCheck this before continuing.
DangerSomething went wrong.

Card · Attribution

Card (.Dual-Card)

Card title
Card body text bound to semantic tokens.

Attribution (.Dual-Attribution)

Jane DoeDesign Systems

Blockquote · Stage

Blockquote (.Dual-Blockquote)

A single SCSS source, two outputs.
— The POC

Stage (.Dual-Stage)

Stage

Hero banner bound to semantic tokens.

Checkbox group · Radio group (sub-components)

Checkbox group (.Dual-CheckboxGroup)

Choose options

Radio group (.Dual-RadioGroup)

Pick one

Tooltip · Typography

Tooltip (.Dual-Tooltip)

Tooltip content on the inverse surface.

Typography (.Dual-Typography)

Title medium bold

§4b — Typography (84 variations · composable utilities)

The 84 variations are 2 families × 16 style-roles × up to 3 weights, reachable via the composable utility axes (iris-font-* · iris-text-* · iris-weight-*) generated from the same type maps — ~21 classes composing to ≥84 combinations (intro roman-only, topline bold-only → 84 not 96).

sans · display-large · bold sans · display-small · bold sans · title-medium · sbold sans · body-x-large · roman sans · body-medium · roman sans · body-x-small · roman slab · title-large · bold slab · quote-large · roman SANS · TOPLINE · BOLD

Each sample composes three utility classes (family + role + weight). Switch the theme in the toolbar — the type re-colors via the semantic --dual-text-* tokens while metrics stay constant.

§5 — Theming and Override Methods

Override methodScopeShadow DOMLight DOM
CSS variable on :rootGlobal✓✓
CSS variable on elementInstance✓✓
SCSS $variable (build-time)Global✓✓
.dual-theme-dark classGlobal✓✓
/* Override any component via CSS vars — works on BOTH paths */
dual-button, .Dual-Button { --dual-button-fill: hotpink; }

/* Or override at the semantic layer (affects all components) */
:root { --dual-action-fill-1: #6b2fb3; }

Both paths are equivalent. The dual architecture ensures a single override surface works for both consumption models.

§6 — Gap Analysis

FeatureDualirisiX
CSS-only usage (no JS)[x][ ][ ]
Per-file imports[x] dist/components/*.css[ ] monolithic[x] theme separate
Component token overrides[x] color-only tier, 14 comps[ ] 1 var[x] 25+ vars
Naming convention[x] SUIT CSS[ ] generic shadow[ ] generic shadow
Utility classes[x] composable type + u-*[x] 84 typo utils[ ] none
CSS Grid system[x] .Grid-cell[ ] none[ ] none
Tree-shaking (CSS)[x] config-driven[ ] bundled[ ] bundled
Framework wrapper needed[ ] no[x] Stencil[x] Stencil

§7 — New capabilities (parameterized type · size scales · subtree modes)

Landed in the POC and compiled into the granular dist/css/*.css layers and the dist/preset/full.css barrel: a parameterized composite typography mixin, content-measure + fluid size scales with a dual-space() multiplier, and attribute-scoped theme modes.

Parameterized typography — type($family,$group,$size,$weight) + base element styles

sans · display · large · bold
sans · title · medium
slab · body · medium (both families emit per group)
sans · quote · large — its own block mixin blockquote()

Base element styles (h1–h6, p, blockquote) map onto type() in the base layer (opt-in). The mixin validates its axes with @error.

Size scales — content-measure, fluid clamp(), and dual-space()

content-small measure (55ch) — a readable line-length cap
fluid-medium clamp() — resize the window
padding = dual-space(3) = calc(var(--dual-spacing) × 3)

Attribute-scoped modes — [data-dual-theme] on a subtree

The theme() mixin now emits both the root .dual-theme-* class and a [data-dual-theme] attribute, so a subtree switches mode independently of the page.

data-dual-theme="light"

data-dual-theme="dark"

data-dual-theme="sand"

iris keeps its iris-ui-theme-* class names; the attribute form is the portable, nestable pattern the POC demonstrates.

§8 — Explore the POC

This overview is the hub. Each area below is its own interactive demo, all rendering against the same built dist/preset/full.css:

DemoShows
Output Architecturedual architecture + config-gated pipeline stages (iris-core build + consumer presets)
Token Architecturethe reference → semantic → component token pipeline
SCSS Structureglobal + component file structure, variable groups, functions, mixins
SUIT CSS & SchemasSUIT class naming + the three machine-readable naming schemas
Layout & Basebase + utilities + grid + 10 primitives, and how they stack & combine
Consumer Theminglive semantic-vs-component variable override
Benchmarks & Comparisonstandardized package benchmarks + adoption impact vs iris & iX