elicit_ui
Typestate-based verified UI system using AccessKit as universal IR.
Overview
elicit_ui provides a formally verifiable UI construction system that
ensures WCAG compliance through typestate patterns, composable constraints,
and proof-carrying contracts. Layouts are constructed as AccessKit trees,
verified against spec-traceable constraints, and rendered through
pluggable backends (egui, ratatui) from a single IR.
Architecture
┌──────────────────────────────────────────┐
│ Constraint System │
│ WCAG · Spatial · Terminal · Custom │
└────────────────┬─────────────────────────┘
│
AccessKit Tree ──→ Layout<Pending> ──→│verify()──→ Layout<Verified>
│
┌─────────────────┤
▼ ▼
EguiBackend RatatuiBackend
(elicit_egui) (elicit_ratatui)
│ │
▼ ▼
Layout<Rendered> Layout<Rendered>
Key Components
- AccessKit Universal IR — all UI represented as accessibility trees
- Typestate State Machine —
Pending → Verified → Rendered - Composable Constraint System — spec-traceable, tiered (hard/structural/advisory)
- Pluggable Backends —
RenderBackendtrait for frontend-agnostic rendering - Terminal Breakpoints — multi-size verification across standard terminal sizes
- Color Contrast — WCAG 1.4.3/1.4.6/1.4.11 contrast ratio verification
- CSS Units — type-safe CSS lengths, breakpoints, zoom invariance
- Proof-Carrying Contracts — formal verification via Kani, Verus, Creusot
State Machine
Layout<Pending> ──verify_a()──→ Layout<Verified> ──render()──→ Layout<Rendered>
──verify_aa()─→
──verify_aaa()→
──verify_custom()→
Layout<Pending>— constructed from an AccessKitTreeUpdate, awaiting verificationLayout<Verified>— all constraints satisfied; exposesnodes()andrender()Layout<Rendered>— rendered through aRenderBackend(egui, ratatui, etc.)
Constraint System
Constraints implement the Constraint trait, each anchored to a recognized standard:
Constraints are composed into a ConstraintSet with enforcement tiers:
let constraints = default
.hard // must pass
.hard // must pass
.advisory // warning only
.build;
WCAG Constraints
| Constraint | WCAG | Level | Description |
|---|---|---|---|
HasLabelConstraint |
4.1.2 | A | Non-empty accessible label |
ValidRoleConstraint |
4.1.2 | A | Valid ARIA role |
KeyboardAccessibleConstraint |
2.1.1 | A | Keyboard navigable |
NoOverflowConstraint |
1.4.10 | AA | Fits within viewport |
MinTouchTargetConstraint |
2.5.5 | AAA | ≥44×44 touch target |
Reflow320 |
1.4.10 | AA | Content reflows at 320px |
TextSpacing |
1.4.12 | AA | Text spacing adjustments |
ResizeText200 |
1.4.4 | AA | Text resizable to 200% |
Spatial Constraints
| Constraint | Standard | Description |
|---|---|---|
GridAlignment |
Material Design 3 | Position snaps to grid step |
MinSpacing |
Design system | Minimum gap between elements |
Terminal Constraints
| Constraint | Standard | Description |
|---|---|---|
TerminalNoOverflow |
WCAG 1.4.10 | Fits cell viewport (cols×rows) |
MinReadableSize |
ISO 9241-3 | Container ≥10 cols × 3 rows |
Constraint Profiles
Pre-built profiles for common verification scenarios:
let verified = layout.verify_with_profile?;
| Profile | Constraints |
|---|---|
WcagA |
HasLabel, ValidRole, KeyboardAccessible |
WcagAA |
Level A + NoOverflow |
WcagAAA |
Level AA + MinTouchTarget |
TerminalAccessible
Convenience builder combining WCAG + terminal constraints:
let constraints = default.to_constraint_set;
// Includes: HasLabel, ValidRole, KeyboardAccessible, TerminalNoOverflow, MinReadableSize
Terminal Breakpoint Verification
Verify a layout across standard terminal sizes in one call:
let breakpoints = standard;
let constraints = default
.hard
.hard
.build;
let report = breakpoints.verify_all;
println!;
Output:
Terminal Breakpoint Report
─────────────────────────────────────────
micro 40×12 [expected-fail] 📝 expected-fail
tiny 60×20 [advisory] ⚠️ warning
VT100 80×24 [required] ✅ pass
small 100×30 [required] ✅ pass
medium 120×40 [required] ✅ pass
large 160×50 [required] ✅ pass
ultrawide 200×60 [required] ✅ pass
─────────────────────────────────────────
Result: PASS (5 pass, 0 fail, 1 warn, 1 expected-fail)
Breakpoint Tiers
| Tier | Meaning |
|---|---|
Required |
Must pass — blocks validity |
Advisory |
Warning only — informational |
ExpectedFail |
Documents known limitations |
Rendering
elicit_ui defines the RenderBackend trait; implementations live in
companion crates:
| Backend | Crate | Description |
|---|---|---|
EguiBackend |
elicit_egui |
Renders to egui widgets |
RatatuiBackend |
elicit_ratatui |
Renders to TuiNode trees |
// After verification, render to any backend:
let = verified.render;
Color Contrast
WCAG contrast ratio verification with palette-based sRGB colors:
use ;
let fg = new; // black
let bg = new; // white
let ratio = contrast_ratio; // 21.0
// Type-level contrast witnesses
let _min: ContrastMinimum = check?; // 4.5:1
let _enh: ContrastEnhanced = check?; // 7:1
CSS Units
Type-safe CSS length parsing and zoom invariance checking:
use ;
let length = Em;
assert!; // relative unit
let px = Px;
assert!; // absolute unit
WCAG Propositions (Compile-Time)
Type-level witnesses that carry proof of compliance:
| Proposition | Description |
|---|---|
HasLabel<T> |
Non-empty accessible label |
ValidRole<T> |
Valid ARIA role |
KeyboardAccessible<T> |
Keyboard navigable |
NoOverflow<T> |
Fits within viewport |
MinTargetSize<T> |
≥44×44 touch target |
AccessibleAA<T> |
Composite Level AA |
Usage
Basic Verification
use ;
use ;
let button_id = from;
let root_id = from;
let mut button = new;
button.set_label;
button.set_bounds;
let mut root = new;
root.set_children;
let update = TreeUpdate ;
let layout = from_update;
let verified = layout.verify_aa?;
assert_eq!;
# Ok::
Custom Constraints
use ;
let constraints = default
.hard
.hard
.advisory
.advisory
.build;
let verified = layout.verify_custom?;
Features
| Feature | Dependencies | Description |
|---|---|---|
emit |
proc-macro2, quote, elicitation/emit |
Code emission for formal verification |
geo |
geo, geo-types |
GeoRust spatial type support |
css |
cssparser |
CSS value parsing |
color |
palette |
sRGB color contrast verification |
layout-engine |
taffy |
Flexbox/grid layout computation |
Formal Verification
When emit is enabled, propositions can generate proofs for:
- Kani — bounded model checking
- Verus — SMT-based verification
- Creusot — deductive verification via Why3
Comparison to Ledger Pattern
| Aspect | Ledger | UI |
|---|---|---|
| Domain | Money transfers | Interactive layouts |
| States | Pending → Validated → Committed | Pending → Verified → Rendered |
| Universal IR | SQL schema | AccessKit tree |
| Propositions | AmountPositive, SufficientFunds | HasLabel, MinTargetSize |
| Backends | SQLite, PostgreSQL, MySQL | egui, ratatui |
| Invariant | Σ debits = Σ credits | All interactive elements accessible |
License
Licensed under Apache-2.0 OR MIT.