Views & Templating
CellUI's view system is incredibly fast because it does not use JSX, Virtual DOMs, or heavy compilation steps. Instead, it relies natively on ES6 Tagged Template Literals via the view function.
The view Function
When you prefix a template literal with view, CellUI parses the HTML string exactly once, creates a native DocumentFragment, and caches it.
The magic happens when you inject ${variables} into the template:
- If you inject a raw string/number, CellUI renders it statically.
- If you inject a
signal(), CellUI leaves a "marker" (__cellui_uid__) in the DOM and binds the signal to that exact spot. - If you inject a
Function, CellUI assumes it is an Event Listener and binds it natively.
import { view, signal } from '@cmj/cellui';
function Welcome() {
const name = signal("Alice");
const updateName = (e: Event) => {
name.value = (e.target as HTMLInputElement).value;
};
return view`
<div class="card">
<h1>Hello, ${name}!</h1>
<input type="text" oninput="${updateName}" value="${name}" />
</div>
`;
}Components are just Functions
Because CellUI components execute exactly once, a "Component" is literally just a function that returns a view. There are no special rules, hooks, or lifecycle methods to memorize!
When you want to nest components, simply call the function:
function App() {
return view`
<main>
${Welcome()}
${Welcome()}
</main>
`;
}Control Flow Expressions
Because CellUI doesn't wipe out the DOM to re-render, you cannot use standard JavaScript map() or if/else inside your view templates if the data is reactive.
Instead, CellUI provides three highly optimized control flow primitives:
when() (Conditionals)
Use when to mount or unmount a component based on a boolean signal. It automatically handles cleaning up DOM nodes when the condition is false.
import { when } from '@cmj/cellui';
const isVisible = signal(false);
return view`
<button onclick="${() => isVisible.value = !isVisible.value}">
Toggle Modal
</button>
${when(isVisible, () => ModalView())}
`;each() (Loops)
Use each to render lists of items. CellUI is smart enough to only append new items or remove deleted ones, instead of re-rendering the entire array.
It requires a unique string property name (like 'id') to track list order and enable O(1) DOM reconciliation.
import { each } from '@cmj/cellui';
const items = signal([ { id: 1, text: 'Buy groceries' } ]);
return view`
<ul>
${each(items, 'id', (item) => view`<li>${item.text}</li>`)}
</ul>
`;match() (Switch Statements)
Use match for complex routing or multi-state rendering.
import { match } from '@cmj/cellui';
const route = signal('home');
return view`
${match(route, {
home: () => HomeView(),
about: () => AboutView(),
contact: () => ContactView(),
})}
`;