euixjs
v0.3.78
Published
EUIX Engine - Ultra-lightweight declarative HTML & XML framework
Maintainers
Readme
Vanilla .EUIX Engine
📄 What is .EUIX Engine?
Make EUIX minimal by default and powerful by opt-in.
A lightweight reactive declarative UI runtime that turns markup + state + events into DOM updates without requiring a build step or a virtual DOM.
The 5 Core Concepts of EUIX
A developer can build reactive applications by learning roughly 5 core concepts:
EUIX
├── 1. State (<data_model>) — typed reactive variables (number, string, boolean, array, object)
├── 2. Templates — expressions {data.count}, conditions (show="{...}" / <if>), and loops (<for_each key="id">)
├── 3. Events & Actions — simple updates (SET, TOGGLE, CALL, EMIT) and JavaScript escape hatch (engine.action)
├── 4. Components — modular reusable definitions (<component_def>), props ({props.name}), and slots
└── 5. Plugins — tree-shakeable opt-in extensions (.use(plugin)) for API, router, storage, charts, etc.Why EUIX?
- 📄 Declarative Markup: State, bindings, and events declared cleanly in standard XML or HTML without complex toolchains or build steps.
- ⚡ Zero Virtual DOM Overhead: Fine-grained direct DOM updates directly mutate affected nodes via
queueMicrotaskbatching. - 🧩 Minimal by Default, Powerful by Opt-In: Tiny Core (~20 KB gzip) with tree-shakeable plugins (
api,router,composer,storage,devtools). - 🛡️ Native Platform First: Standard HTML & CSS styling, container event delegation, and direct browser APIs over bloated custom abstractions.
- 🤖 AI-Agent Friendly: Structured XML specs allow LLMs to deterministically parse, generate, and edit UI components without syntactic ambiguity.
📖 Agent & Architecture Guide: For complete internal runtime architecture, AST caching, and plugin hooks, see .agents/AGENTS.md.
⚡ Performance Benchmarks (js-framework-benchmark standard)
EUIX Engine is engineered for maximum performance on modern web applications with zero Virtual DOM overhead:
| Benchmark Scenario | Initial Baseline | Optimized EUIX Engine | Performance Gain |
| :--- | :--- | :--- | :--- |
| Fine-Grained Single Item Update | 15.41 ms | 0.21 ms | ⚡ ~99% Faster |
| Swap 2 Rows (1,000 items) | 1,762.45 ms | 12.79 ms | 🚀 ~99.3% Faster |
| Partial Update (every 10th row) | 530.40 ms | 28.05 ms | ⚡ ~95% Faster |
| Clear All 1,000 Rows | 420.10 ms | 5.26 ms | 🧹 ~98.7% Faster |
| 3,000 Item Bulk Render | 2,609.51 ms | 439.09 ms | 🚀 ~83% Faster |
| 1,000 Item Bulk Render | 2,007.30 ms | 246.45 ms | ⚡ ~88% Faster |
| Append 1,000 Rows (Total 2,000) | 1,289.50 ms | 131.13 ms | 🚀 ~90% Faster |
| Virtual Scrolling (10,000 items) | N/A | 6.31 ms | ⚡ 60 FPS Windowing |
| Interaction Latency (Click -> DOM) | 15.41 ms | 2.74 ms | ⚡ ~82% Faster |
| Initial XML Mount Latency | 125.74 ms | 22.37 ms | 🚀 ~82% Faster |
🚀 Quick Start
1. Embedded HTML Script Spec (type="application/euix")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vanilla .EUIX Quickstart</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/euixjs@latest/dist/EUIXEngine.umd.js"></script>
</head>
<body class="bg-slate-100 min-h-screen flex items-center justify-center p-6">
<div id="app" class="w-full max-w-md"></div>
<!-- Declarative EUIX Application Spec -->
<script type="application/euix" target="#app">
<uid_spec>
<data_model>
<state id="counter" type="number">0</state>
<state id="tasks" type="array">[{"id": 1, "title": "Learn EUIX Core", "done": false}]</state>
</data_model>
<div class="p-6 bg-white rounded-2xl shadow-xl border border-slate-100 flex flex-col gap-4">
<div class="flex items-center justify-between">
<h1 class="text-xl font-bold text-slate-800">Counter: {data.counter}</h1>
<span class="px-2.5 py-1 bg-indigo-50 text-indigo-700 font-semibold text-xs rounded-lg">Zero VDOM</span>
</div>
<div class="flex gap-2">
<button on_click:set="counter={data.counter + 1}" class="flex-1 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white font-bold rounded-xl text-sm transition">
➕ Increment
</button>
<button on_click:set="counter=0" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 text-slate-700 font-bold rounded-xl text-sm transition">
Reset
</button>
</div>
<!-- List Rendering with Keyed DOM Reconciliation -->
<div class="flex flex-col gap-2 pt-2 border-t border-slate-100">
<for_each items="{data.tasks}" var="task" key="id">
<div class="p-3 bg-slate-50 rounded-xl flex items-center justify-between border border-slate-100">
<span class="text-sm font-medium text-slate-700">{task.title}</span>
<button on_click:mutate="tasks.REMOVE where id={task.id}" class="text-rose-500 hover:bg-rose-50 p-1 rounded-lg text-xs font-bold">
✕ Delete
</button>
</div>
</for_each>
</div>
</div>
</uid_spec>
</script>
</body>
</html>2. JavaScript / ESM Import Options
Option A: Minimal Default Import (Recommended)
import { EUIX } from 'euixjs';
// or: import { EUIXEngineCore } from 'euixjs/core';
// Optional: Register plugins as needed
import { EUIXApiPlugin } from 'euixjs/api';
import { EUIXRouterPlugin } from 'euixjs/router';
EUIX.use(EUIXApiPlugin).use(EUIXRouterPlugin);
// Register JavaScript business logic actions cleanly
EUIX.action('saveUser', async (args, { $data }) => {
console.log('Saving user:', args.userId);
$data.status = 'saved';
});
// Mount to DOM
const engine = EUIX.mount(xmlString, '#app');Option B: Full Bundle (euixjs/full)
For convenience when all plugins (API, Router, Composer, Storage, DevTools) are desired out of the box:
import { EUIXEngine } from 'euixjs/full';
const engine = EUIXEngine.mount(xmlString, '#app');📦 Subpath Package Exports & Bundle Metrics
| Subpath Import | Module / Description | Minified Size (UMD / ESM) | Compressed (Gzip / Brotli) |
| :--- | :--- | :--- | :--- |
| euixjs/core | EUIXEngineCore (Lite Core Build) | 126.3 kB / 241.6 kB | 34.3 kB / 29.2 kB |
| euixjs | EUIXEngine (Full Bundle Build) | 252.2 kB / 477.5 kB | 67.9 kB / 56.3 kB |
| euixjs/router | Web Router Engine (Data, Outlets, History) | 82.2 kB (ESM) | 17.2 kB / 14.9 kB |
| euixjs/chart | Declarative Chart.js (v4.x) Integration | 20.8 kB (ESM) | 4.5 kB / 3.9 kB |
| euixjs/leaflet | Declarative Leaflet Maps & GIS | 26.6 kB (ESM) | 6.2 kB / 5.4 kB |
| euixjs/api | REST SWR HTTP Client Engine | 24.0 kB (ESM) | 5.1 kB / 4.5 kB |
| euixjs/animation | Declarative Animation System | 20.2 kB (ESM) | 4.2 kB / 3.7 kB |
| euixjs/composer | Action Composer Workflow Engine | 17.9 kB (ESM) | 4.1 kB / 3.6 kB |
| euixjs/resilience | Resilience Execution Primitives | 15.4 kB (ESM) | 3.4 kB / 3.0 kB |
| euixjs/reactive | Watch & Computed State System | 13.6 kB (ESM) | 3.3 kB / 2.9 kB |
| euixjs/navigator | Device & Browser Capabilities | 12.1 kB (ESM) | 2.6 kB / 2.2 kB |
| euixjs/head | Declarative Head & Helmet Meta | 7.1 kB (ESM) | 1.6 kB / 1.3 kB |
| euixjs/dialog | Modal Dialog Overlay Component | 5.0 kB (ESM) | 1.5 kB / 1.3 kB |
| euixjs/dnd | HTML5 & Pointer Drag and Drop | 5.0 kB (ESM) | 1.4 kB / 1.2 kB |
| euixjs/storage | State Storage & Persistence | 3.3 kB (ESM) | 1.0 kB / 0.9 kB |
| euixjs/collapse | Accordion / Collapse Component | 3.3 kB (ESM) | 1.1 kB / 0.9 kB |
| euixjs/webmcp | WebMCP Browser AI Agent Plugin (document.modelContext) | 28.6 kB (ESM) | 6.7 kB / 5.8 kB |
| euixjs/devtools | DevTools Inspector & WebMCP Panel | 62.1 kB / 85.5 kB | 14.2 kB / 17.4 kB |
✨ Features & Capabilities
- 🤖 WebMCP Browser AI Agent Plugin (
<webmcp>,<tool>,document.modelContext): Expose application state and Action Composer workflows directly to browser AI agents without external dependencies. Features progressive enhancement, automatic JSON Schema parameter compilation, sandboxed context (state,actions,router), error sanitization, and DevTools inspection panel. - ⚡ Action Composer System (
<action_def>,<param>,<return>): Define reusable named action workflows with parameters (required="true",default="..."), sequential step execution, nested action calls,{result}data flow propagation, circular loop guards, and programmatic execution (engine.executeAction()). - 👁️ Viewport Lazy Loading (
<import lazy="true" viewport="true" />): On-demand asynchronous component loading triggered viaIntersectionObserverwith configurableroot_margin(e.g.200px) as the user scrolls into view. - 🗂️ Native & Pointer Drag & Drop (
draggable="true",<on_dragstart>,<on_drop>): Fine-grained HTML5 & Pointer Drag & Drop support with zero-lag custom floating drag preview (#euix-drag-ghost) and automaticdragoverpreventDefault handling. - 🔀 Reactive List Mutations (
MUTATE_STATEPUSH,REMOVE,UPDATE,SWAP,MOVE_UP,MOVE_DOWN): High-performance array list mutations including item insertion, property updates, index deletion, item swapping (SWAP), and quick index reordering (MOVE_UP,MOVE_DOWN). - 🔄 SWR API Revalidation (
REVALIDATE_API,<revalidate>): Stale-While-Revalidate API data refetching triggered declaratively or programmatically (revalidateApi()). - ⚡ Action Shorthand Syntax (
on_click:set,on_click:toggle,on_click:mutate): Concise, attribute-based declarative state updates, boolean toggling, and array mutations without verbose child XML tags (on_click:set="count={data.count + 1}",on_click:toggle="isOpen",on_click:mutate="items.PUSH({...})",on_change:set="username"). - 📝 Form Input Modifiers & Automatic Type Coercion (
bind.number,bind.trim,bind.boolean,bind.lazy): Automatic numeric parsing on<input type="number">or<input bind.number="...">, string trimming on<input bind.trim="...">, native boolean storage on<input type="checkbox" bind.boolean="...">, and deferred updates on change/blur with<input bind.lazy="...">. - 🎨 Design Tokens & Constants (
<constants>,<vars>): Define reusable CSS utility classes, design tokens, or API URLs at root or component level and reference them via{const.key}or{var.key}(supports external JSON files viasrc="..."). - 📡 Declarative & Component-Scoped API Client (
<api_config>): Configurable base URL (base_url="..."), CORS credentials (include/same-origin), default headers, timeouts, and request/response interceptors with zero-leakage component-level scoping.- Base URL Resolution Rules:
- Action attribute
base_urloverrides component & global defaults. - Relative paths starting with
./or../(e.g.<url>./components/App.xml</url>), or actions withignore_base_url="true"/base_url="", automatically bypassapi_config.base_urlto safely load local assets without domain prepending.
- Action attribute
- Base URL Resolution Rules:
- 📁 External JSON Resource Loading (
src="..."): Declaratively fetch initial<data_model>states,<constants>tokens, or individual<state>values directly from JSON files (<data_model src="...">,<constants src="...">,loadDataModel(),loadConstants(),mountAsync()). - ⏱️ Lifecycle Timers & Intervals (
<on_interval>): Declarative recurring timers with conditional evaluation (if="...") and automatic unmount cleanup. - 📜 External Scripts & Inline Scripting (
<use_script>,<use_style>,RUN_SCRIPT): Declaratively load external JS libraries (e.g. Highlight.js, Canvas-Confetti) and CSS stylesheets. Execute custom JS code snippets safely inside<on_mount>,<on_state_change>, or<on_click>usingaction="RUN_SCRIPT"with$el,$data,$engine, and$evtinjected in anew Function()sandbox (noeval()). - 🛑 Infinite Loop Guard: Built-in reactivity cascade depth guard (>50 updates), component recursion depth guard (>20 depth), and circular action recursion guard preventing browser freezes or crashes.
- 🛠️ EUIX DevTools Inspector: Floating Inspector, real-time State Tree Inspector, and Action Log Stream panel with global
$stateand$engineconsole exposure. - 🛡️ Contract & E2E Test Suite: Fully verified with 14 Vitest unit/component/contract/benchmark test files (100% passing) and Playwright E2E browser tests.
📁 External JSON Resource Loading (src="...")
EUIX Engine supports fetching initial <data_model> states, design token <constants>, or individual <state> values directly from external JSON files:
<uid_spec>
<!-- Load design tokens from JSON file -->
<constants src="/data/app-tokens.json" />
<!-- Load initial data model states from JSON file -->
<data_model src="/data/app-config.json">
<!-- Local fallback states -->
<state id="local_counter">0</state>
<!-- Single state from JSON file -->
<state id="user_profile" src="/api/profile.json" />
</data_model>
<flex direction="column">
<span class="{const.info_banner}">Portal Status: {data.portal_status}</span>
</flex>
</uid_spec>Programmatic JS API:
const engine = new EUIXEngine("#app");
await engine.loadDataModel("/data/app-config.json");
await engine.loadConstants("/data/app-tokens.json");📜 Declarative External Scripts & Inline Scripting (<use_script>, <use_style>, RUN_SCRIPT)
EUIX Engine supports declaratively loading external JavaScript libraries (e.g. Highlight.js, Canvas-Confetti, Chart.js) and CSS stylesheets directly inside XML templates without writing manual script loader boilerplate.
Custom JavaScript snippets can be executed safely inside lifecycle hooks or event handlers using action="RUN_SCRIPT" (backed by a new Function() sandbox, avoiding eval()):
<uid_spec>
<!-- Declarative External JS & CSS Loaders -->
<use_script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" />
<use_style src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css" />
<use_script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js" />
<flex direction="column" gap="16">
<!-- Highlight.js Syntax Highlighting on Mount or State Change -->
<pre class="bg-slate-900 p-4 rounded-xl">
<code class="language-javascript">
<on_mount action="RUN_SCRIPT">
if (window.hljs) window.hljs.highlightElement($el);
</on_mount>
const engine = new EUIXEngine("#app");
engine.mount(xmlSpec);
</code>
</pre>
<!-- Canvas Confetti Explosion on Button Click -->
<button class="px-4 py-2 bg-emerald-600 text-white font-bold rounded-xl">
<on_click action="RUN_SCRIPT">
if (window.confetti) confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } });
</on_click>
🎉 Celebrate & Complete Order
</button>
</flex>
</uid_spec>⚡ Action Shorthand Syntax (on_click:set, on_click:toggle, on_click:mutate)
Simplify your templates by writing common actions directly as attributes without verbose <on_click action="..."> boilerplate:
<uid_spec>
<data_model>
<state id="counter" type="number">0</state>
<state id="is_open" type="boolean">false</state>
<state id="items" type="array">[{"id": 1, "title": "First"}]</state>
</data_model>
<flex direction="column" gap="8">
<!-- 1. State Set Shorthand (Math arithmetic & property assignment) -->
<button on_click:set="counter={data.counter + 1}">+1</button>
<input on_change:set="user_name" placeholder="Two-way update" />
<!-- 2. Boolean Toggle Shorthand -->
<button on_click:toggle="is_open">Toggle Modal ({data.is_open ? 'OPEN' : 'CLOSED'})</button>
<!-- 3. Array Mutation Shorthand (PUSH, REMOVE, CLEAR) -->
<button on_click:mutate="items.PUSH({id: 2, title: 'Second'})">Add Item</button>
<for_each items="{data.items}" var="item" key="id">
<div>
<span>{item.title}</span>
<button on_click:mutate="items.REMOVE where id={item.id}">✕</button>
</div>
</for_each>
<!-- 4. API Revalidate & Script Execution -->
<button on_click:revalidate="get_users">Refresh Users</button>
<button on_click:run="$data.counter += 10">Add 10 (Script)</button>
</flex>
</uid_spec>Declarative In-Template & Scoped Styles (<style>, <style scoped="true">)
<uid_spec>
<!-- Dynamic Reactive Styles with State Interpolation -->
<style>
:root {
--brand-color: {data.themeColor};
}
.header-title {
color: var(--brand-color);
font-weight: 800;
}
</style>
<!-- Scoped Component Styling (Isolated to component via [data-euix-scope]) -->
<component_def name="user-badge" isolated="true">
<style scoped="true">
:host {
display: inline-flex;
}
.badge {
background: #0f172a;
border-radius: 8px;
padding: 6px 12px;
}
</style>
<div class="badge">
<span>{data.userName}</span>
</div>
</component_def>
</uid_spec>🧩 Modular Components & Scoped Slots (<slot var="..." /> & <template let="..." />)
Build highly customizable, reusable components by exposing scoped props from <slot> elements to parent consumers:
<uid_spec>
<data_model>
<state id="users" type="array">[{"id": 1, "name": "Alice", "role": "Lead"}, {"id": 2, "name": "Bob", "role": "Dev"}]</state>
</data_model>
<!-- 1. Component Definition with Scoped Slot -->
<component_def name="data-grid">
<div class="grid-table">
<for_each items="{props.items}" var="row" key="id">
<div class="grid-row">
<!-- Pass row and index to parent consumer -->
<slot name="row" item="{row}" index="{$index}">
<!-- Fallback content if no custom slot is provided -->
<span>{row.name}</span>
</slot>
</div>
</for_each>
</div>
</component_def>
<!-- 2. Consumer Projection with Template & Scoped Let -->
<component name="data-grid" items="{data.users}">
<template slot="row" let="s">
<div class="custom-card">
<strong>#{s.index + 1}:</strong> {s.item.name} <span class="badge">{s.item.role}</span>
</div>
</template>
</component>
</uid_spec>Injected Script Scope Variables:
$el: Target DOM element executing the script.$data: Fine-grained reactive EUIX state Proxy object.$engine: The active EUIXEngine instance.$evt: Triggering DOM Event object (if executed from an event handler).
// Flicker-free async mount (awaits all external JSON resources before rendering)
const engine = await EUIXEngine.mountAsync(xml, '#app');📊 Declarative Chart.js (v4.x) Integration (euixjs/chart)
Render and control Chart.js charts directly in XML with reactive state binding, declarative actions, and event bridging with zero Chart.js code bundled in EUIX core:
npm install euixjs chart.jsESM Usage:
import { EUIXEngineCore } from 'euixjs/core';
import { EUIXChartPlugin } from 'euixjs/chart';
import Chart from 'chart.js/auto';
// Inject Chart.js constructor
EUIXChartPlugin.configure({ Chart });
EUIXEngineCore.use(EUIXChartPlugin);
const engine = EUIXEngineCore.mount(xmlSpec, '#app');Declarative XML Syntax:
<uid_spec>
<data_model>
<state id="sales_chart" type="object">
{
"type": "bar",
"data": {
"labels": ["Q1", "Q2", "Q3", "Q4"],
"datasets": [{ "label": "Sales ($k)", "data": [45, 62, 78, 95] }]
},
"options": { "responsive": true, "maintainAspectRatio": false }
}
</state>
</data_model>
<flex direction="column" gap="16">
<!-- Declarative <chart> Element -->
<chart
id="sales"
config="{data.sales_chart}"
height="320"
update_mode="none"
>
<on_chart_click action="RUN_SCRIPT">
console.log("Clicked:", $evt.detail.label, $evt.detail.value);
</on_chart_click>
</chart>
<!-- Declarative Actions -->
<flex direction="row" gap="8">
<button class="btn">
<on_click action="CHART_TOGGLE_DATASET" chart="sales" dataset_index="0" />
Toggle Dataset
</button>
<button class="btn">
<on_click action="CHART_EXPORT_IMAGE" chart="sales" target="data.exported_png" />
Export PNG
</button>
</flex>
</flex>
</uid_spec>Imperative API (engine.chart):
engine.chart.get('sales'); // Access underlying Chart.js instance
engine.chart.update('sales', 'none'); // In-place update with mode
engine.chart.show('sales', 0); // Show dataset 0
engine.chart.hide('sales', 0); // Hide dataset 0
engine.chart.toggleDataset('sales', 0); // Toggle dataset visibility
engine.chart.toggleData('sales', 2); // Toggle data point visibility
engine.chart.toBase64Image('sales'); // Export base64 image🧩 Dual-Mode State Architecture: Component-Scoped Isolation & Global Stores
EUIX Engine supports a versatile Dual-Mode State System that enables both Application-Wide Shared Stores and Strict Component-Scoped Instance Isolation:
+-----------------------------------+
| Central Global State Pool |
| (data.*, global.*, states.xml) |
+-----------------------------------+
^
| (reads / writes)
+-----------------------+-----------------------+
| |
v v
+-----------------------------+ +-----------------------------+
| Component Instance 1 | | Component Instance 2 |
| (e.g. <accordion-card />) | | (e.g. <accordion-card />) |
+-----------------------------+ +-----------------------------+
| Private Local State | | Private Local State |
| (local.isOpen = true) | | (local.isOpen = false) |
+-----------------------------+ +-----------------------------+1. Global / Shared State Store (states.xml / scope="global")
When a component or external file (e.g. states.xml) defines global states or uses <data_model scope="global">, its states are merged into the central state pool and become accessible across the entire application:
<!-- components/states.xml -->
<component_def name="app-store">
<data_model scope="global">
<state id="theme">dark</state>
<state id="user" type="object">{"name": "Ahmet", "role": "Admin"}</state>
</data_model>
</component_def>2. Component-Scoped Instance Isolation (isolated="true" / scope="local")
When a component is marked with isolated="true" (or <data_model scope="local"> / <state scope="local">), each rendered instance of that component receives its own independent reactive state. Mutating local state on one instance does not affect any other instance:
<!-- components/AccordionCard.xml -->
<component_def name="accordion-card" isolated="true">
<data_model>
<state id="isOpen" type="boolean">false</state>
<state id="clicks" type="number">0</state>
</data_model>
<div class="card-box">
<h3>{props.title}</h3>
<p>Status: {local.isOpen ? 'OPEN' : 'CLOSED'}</p>
<p>Clicks: {local.clicks}</p>
<!-- Mutates ONLY this component instance's state -->
<button class="btn">
<on_click action="SET_STATE">
<path>local.isOpen</path>
<value>{local.isOpen ? 'false' : 'true'}</value>
</on_click>
<on_click action="SET_STATE">
<path>local.clicks</path>
<value>{local.clicks} + 1</value>
</on_click>
Toggle Card
</button>
</div>
</component_def>3. Hybrid State Access (Local + Global in the Same Component)
An isolated component can seamlessly access and mutate both its private local state (local.*) and application-wide global state (global.* or data.*):
<component_def name="user-panel" isolated="true">
<data_model>
<state id="panel_open" type="boolean">false</state>
</data_model>
<div class="panel {data.theme}">
<span>User: {data.user.name}</span>
<span>Panel: {local.panel_open ? 'Open' : 'Closed'}</span>
<!-- Mutates local instance state -->
<button>
<on_click action="SET_STATE">
<path>local.panel_open</path>
<value>{local.panel_open ? 'false' : 'true'}</value>
</on_click>
Toggle Panel
</button>
<!-- Mutates global application state -->
<button>
<on_click action="SET_STATE">
<path>global.theme</path>
<value>{data.theme == 'dark' ? 'light' : 'dark'}</value>
</on_click>
Switch Theme
</button>
</div>
</component_def>🔒 Component Isolation & Scoping Matrix
Below is a reference of how metadata & configuration tags behave regarding component scoping vs global state:
| Tag / Feature | Scope Level | Leakage Risk | Scoping Behavior & Precedence |
| :--- | :--- | :--- | :--- |
| isolated="true" / scope="local" | Component Instance | 🟢 Zero Leakage | Isolated state (local.*) is instantiated per rendered component instance. Multiple copies maintain completely separate state. |
| states.xml / scope="global" | Global Reactive Store | 🟢 By Design | Shared stores merge their <data_model> into the global data.* pool, accessible by root and all components. |
| <api_config> | Component & Global | 🟢 Zero Leakage | Component-level <api_config> overrides global config for all XHR calls within that component tree. |
| <constants> / <vars> | Component & Global | 🟢 Zero Leakage | Component design tokens inherit from parent components and override parent/global constants locally. |
| <on_mount>, <on_interval> | Component & Element | 🟢 Zero Leakage | Timers and lifecycle hooks are tied strictly to the lifecycle of the mounting component instance. |
🎨 Constants & Design Tokens (<constants>, <vars>)
Define reusable CSS utility class tokens or configuration variables at root or component level:
<uid_spec>
<constants src="data/app-tokens.json">
<const id="card_box">w-full bg-white p-6 rounded-2xl shadow-xl shadow-slate-200/50 border border-slate-100</const>
<const id="btn_primary">px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl text-sm transition-colors cursor-pointer</const>
<const id="badge_blue">px-2.5 py-1 bg-blue-50 text-blue-700 font-semibold rounded-lg text-xs</const>
</constants>
<vars>
<var id="app_title">EUIX Engine Portal</var>
</vars>
<flex direction="column" class="{const.card_box}">
<span class="{const.badge_blue}">{var.app_title}</span>
<button class="{const.btn_primary}">Submit</button>
</flex>
</uid_spec>🛡️ Declarative Try / Catch / Finally Error Handling (<try>, <catch var="err">, <finally>)
EUIX Engine supports declarative, structured error handling across both synchronous and asynchronous actions (XHR, RUN_SCRIPT, Action Composer workflows).
<uid_spec>
<flex direction="column" gap="12">
<button class="btn">
<on_click action="TRY">
<!-- Protected Actions -->
<step action="XHR">
<url>https://api.example.com/data</url>
<method>POST</method>
</step>
<!-- Catch Scope: Executes if Try throws or rejects -->
<catch var="err">
<step action="SET_STATE">
<path>data.error_message</path>
<value>[{err.code}] {err.message} (Status: {err.status})</value>
</step>
</catch>
<!-- Finally Scope: Always executes after Try / Catch -->
<finally>
<step action="SET_STATE">
<path>data.is_loading</path>
<value>false</value>
</step>
</finally>
</on_click>
Submit Data
</button>
</flex>
</uid_spec>Structured Error Object (EUIXStructuredError)
Errors caught inside <catch var="err"> provide structured properties:
{err.message}: Human-readable error message{err.code}: Categorized error code (ACTION_EXECUTION_ERROR,API_HTTP_ERROR,API_NETWORK_ERROR,VALIDATION_ERROR,TIMEOUT_ERROR){err.status}: HTTP status code (e.g. 500, 404) for network errors{err.originatingAction}: Action or tag name that produced the failure{err.component}: Originating component name<rethrow />: Explicitly re-throw caught error to propagate to parent scope
Visual Component Fallback (Inline Error Boundary)
When an XML element or custom component fails during rendering, EUIX Engine isolates the failure and renders a graceful inline error fallback element (.euix-error-fallback) without unmounting or crashing the rest of the application tree:
<!-- Automatically rendered inline on component render failure -->
<div class="euix-error-fallback">⚠️ Component Error: <broken_component></div>Programmatic Global Error Handler (engine.onError)
Register a global onError callback on the engine instance to capture all uncaught runtime errors, XML parsing failures, XHR errors, or component rendering exceptions for telemetry or error monitoring (e.g. Sentry, LogRocket):
const engine = EUIXEngine.mount(xmlString, '#app');
engine.onError = (error, contextInfo) => {
console.error(`[EUIX Error Boundary] ${contextInfo}:`, error);
// Send to logging or error reporting service
};⚡ Declarative Resilience Primitives & EUIXResiliencePlugin (<retry>, <timeout>, <delay>)
EUIX Engine provides tree-shakeable resilience execution primitives (<retry>, <timeout>, <delay>, EUIXCancellationController) via EUIXResiliencePlugin:
<uid_spec>
<flex direction="column" gap="12">
<button class="btn">
<on_click action="TRY">
<!-- Retry with Exponential Backoff Strategy -->
<retry attempts="3" delay="500" backoff="exponential" max_delay="3000" on_error="API_HTTP_ERROR,API_NETWORK_ERROR,TIMEOUT_ERROR">
<timeout ms="2000" message="Request timed out after 2 seconds">
<step action="XHR">
<url>https://api.example.com/data</url>
<target>data.items</target>
</step>
</timeout>
</retry>
<delay ms="500" />
<catch var="err">
<step action="SET_STATE">
<path>data.error_message</path>
<value>[{err.code}] {err.message}</value>
</step>
</catch>
</on_click>
Resilient Fetch
</button>
</flex>
</uid_spec>⚡ Watch & Computed State (EUIXReactivePlugin - <computed>, <watch>)
EUIX Engine provides tree-shakeable derived state (<computed>) and reactive side-effect watchers (<watch>) via EUIXReactivePlugin (euixjs/reactive):
<uid_spec>
<data_model>
<state id="firstName">Jane</state>
<state id="lastName">Smith</state>
<state id="user_role">Admin</state>
<state id="searchQuery"></state>
<!-- 1. Memoized Computed Derived Property -->
<computed id="fullName" deps="firstName, lastName">
return $data.firstName + " " + $data.lastName;
</computed>
<!-- 2. Reactive Watcher Declared Inside <data_model> -->
<watch path="searchQuery">
<step action="REVALIDATE_API" tag="get_countries" />
</watch>
</data_model>
<!-- 3. Side-Effect Watcher Triggering Actions on Change -->
<watch path="user_role">
<step action="MUTATE_STATE">
<path>audit_logs</path>
<operation>UNSHIFT</operation>
<value>Role changed from {prevValue} to {newValue}</value>
</step>
</watch>
<flex direction="column">
<h1>Welcome, {data.fullName}!</h1>
</flex>
</uid_spec>🎭 Declarative Animation System (EUIXAnimationPlugin - <animation_def>, <animate>)
EUIX Engine provides a complete keyframe animation engine with enter and deferred leave transitions (euixjs/animation):
<uid_spec>
<!-- 1. Reusable Keyframe Animation Definition -->
<animations>
<animation_def name="customPulse" duration="400" easing="ease-in-out">
<keyframe offset="0" transform="scale(1)" opacity="1" />
<keyframe offset="0.5" transform="scale(1.1)" opacity="0.8" />
<keyframe offset="1" transform="scale(1)" opacity="1" />
</animation_def>
</animations>
<flex direction="column" gap="16">
<!-- 2. Enter and Deferred Leave Lifecycle Transitions -->
<div id="hero" enter_animation="slide-in-down" leave_animation="fade-out">
<h1>Animated Element</h1>
</div>
<!-- 3. Event-Triggered Declarative Animation Action -->
<button class="btn">
<on_click action="ANIMATE" target="#hero" name="customPulse" duration="500" />
Animate Hero
</button>
</flex>
</uid_spec>🛡️ Declarative Error Boundaries (<error_boundary>)
EUIX Engine provides built-in declarative error boundaries (<error_boundary>, <error-boundary>, <boundary>) to catch and isolate unhandled runtime exceptions, component loading/mounting failures, and expression errors:
<uid_spec>
<flex direction="column" gap="16">
<!-- Error Boundary with Rich Fallback & Retry Action -->
<error_boundary name="FeedBoundary" on_error="alert_count={data.alert_count + 1}">
<component src="./live-feed.xml" />
<fallback let="err">
<div class="card p-4 border border-red-300 bg-red-50 rounded-xl text-red-800">
<h3>⚠️ Failed to load feed</h3>
<p class="text-sm">{err.message}</p>
<button class="btn btn-sm mt-2" on_click:retry="FeedBoundary">
🔄 Retry Feed
</button>
</div>
</fallback>
</error_boundary>
</flex>
</uid_spec>🛠️ EUIX DevTools & Performance Profiler
Enable DevTools inspect overlay and floating drawer panel by pressing Alt + Shift + I or clicking the 📊 State & Logs button:
- 📊 State Inspector & Live Editor: Live real-time inspection, type badges (
number,string,boolean,array,object), inline live editing, boolean toggle switches, stepper buttons, expandable JSON editor (✏️ Edit JSON), dynamic state creation (➕ Add), and deletion (🗑️). - ⚡ Reactivity Visual Flash (
⚡ Flash/highlightUpdates): Real-time glowing visual outline highlighting all impacted DOM elements as reactive state updates. - 📜 Action Logs: Real-time stream of all executed actions (
SET_STATE,MUTATE_STATE,XHR). - ⏱️ Time-Travel State History: Complete undo/redo timeline snapshots with visual diff inspection.
- ⚡ Performance Profiler (
engine.getPerformanceMetrics()): Live monitoring of initial mount time (ms), active reactive DOM bindings, unique elements count, AST cache hit ratio, state watchers, and JS heap memory. - 🛡️ Visual XML Error Code Frames (
EUIXXMLParseError): Precise line and column error reporting with visual code snippet pointers on malformed XML specifications. - 💻 Console Exposure: Access
window.$state,window.$engine, andwindow.$euixdirectly in browser dev console.
🟦 TypeScript State Schema & Generic Typing
EUIX Engine includes first-class TypeScript support with generic state typing:
import { EUIXEngine } from 'euixjs';
interface AppState {
counter: number;
userName: string;
isOnline: boolean;
todos: Array<{ id: number; title: string }>;
}
const xml = `
<uid_spec>
<data_model>
<state id="counter" type="number">0</state>
<state id="userName">Guest</state>
<state id="isOnline" type="boolean">true</state>
<state id="todos" type="array">[]</state>
</data_model>
</uid_spec>
`;
// Mount with strongly-typed state schema
const engine = EUIXEngine.mount<AppState>(xml, '#app');
// Inferred return types
const count: number = engine.getState('counter');
const user: string = engine.getState('userName');
// Type-checked updates
engine.setState('counter', 42);
engine.setState({ counter: 50, isOnline: false });
engine.mutateState('todos', 'PUSH', { id: 1, title: 'Build UI' });🛡️ Battle-Testing & Release Verification Suite
EUIX Engine is systematically battle-tested under malformed input, concurrency, cancellation, long-running workloads, and complex execution combinations.
Test Architecture Overview
- Property-Based Testing (
fast-check): Validates structural invariants across randomly generated valid EUIX applications. - Invalid Input Fuzzing: Tests hostile XML, unclosed tags, duplicate state IDs, 150-depth DOM nesting, and circular computed dependencies (
COMPUTED_CYCLE_ERROR) without process crashes. - AST Round-Trip Equivalence: Asserts
XML -> Spec AST -> JSON -> Spec AST -> XMLsemantic equivalence. - Action Permutation Engine: Tests nested combinations of
TRY,RETRY,TIMEOUT,DELAY,COMPOSED_ACTION,XHR,MUTATE_STATE. - Async Chaos & Late Mutation Protection: Uses a seedable PRNG to simulate network delays and guarantees that timed-out/cancelled operations CANNOT mutate state after scope exit.
- Torture Suites & Stress Fixtures: Includes 10k reactive storms, 5-level computed DAG torture, 200 cycle mount/unmount leak checks, resource single-disposal (
dispose()), and 4 permanent engineering stress fixtures (StressDashboard, HugeList, WorkflowHell, LifecycleHell). - Package Artifact Smoke Test: Builds, packs (
npm pack), extracts, and verifies UMD/ESM distribution integrity. - Cross-Browser Matrix: Playwright testing across Chromium, Firefox, and WebKit.
Test Commands
# Fast Unit & Integration Suite (185 tests)
npm test
# Battle-Testing Suite (Property, Fuzz, Chaos, Permutations, Torture)
npm run test:battle
# Playwright Cross-Browser Matrix (Chromium, Firefox, WebKit)
npm run test:browser
# Configurable Duration Soak Load Test
npm run test:soak
# Package Artifact Tarball Smoke Test
npm run test:package
# Full Release Verification Gate (Build, Unit, Battle, Package Smoke Dashboard)
npm run verify:release