Expressions
Dynamic values, bindings, conditionals, and event handlers. Expressions are how KERN nodes connect to runtime state.
Expression blocks {{ }}
Double curly braces embed JavaScript expressions into any prop value. The parser treats {{ ... }} as a single expression token.
state name=count initial={{ 0 }}
state name=items initial={{ [] }}
text value={{ count + " items" }}
text value={{ loading ? "Loading..." : "Ready" }}Expressions can contain any valid JavaScript — ternaries, function calls, template literals, array methods.
Two-way binding: bind=
The bind= prop creates two-way data binding between an input and a state variable. The compiler auto-generates the setter.
state name=query initial=""
input bind=query placeholder="Search..."Compiles to React:
const [query, setQuery] = useState('');
<input value={query} onChange={(e) => setQuery(e.target.value)}
placeholder="Search..." />bind= works on input, textarea, slider, and toggle nodes. Each generates the appropriate setter pattern for its input type.
Event handlers: onClick=
Button nodes accept onClick= with either a bare value or an expression block:
button text="Increment" onClick={{ () => setCount(c => c + 1) }}
button text="Reset" onClick={{ () => setCount(0) }}When onClick= is present, the compiler marks the component as a client component (adds 'use client' in Next.js).
Event handlers: on event=
The on node defines event handlers that compile to useCallback + useEffect for global listeners in React, or onMounted/onUnmounted in Vue:
screen name=App
on event=click
handler <<<
setCount(prev => prev + 1);
>>>
on event=key key=Enter
handler <<<
processInput(buffer);
>>>
on event=submit async=true
handler <<<
e.preventDefault();
await saveForm(data);
>>>Supported events include: click, key, keydown, keyup, submit, change, focus, blur, and scroll. Each gets the correct React event type (React.MouseEvent, React.KeyboardEvent, etc.).
The key= prop on keyboard events adds an automatic guard:
// on event=key key=Enter compiles to:
const handleKey = useCallback((e: React.KeyboardEvent) => {
if (e.key !== 'Enter') return;
processInput(buffer);
}, []);Conditional rendering: conditional if=
The conditional node renders its children only when the if= expression is truthy:
conditional if={{ !loading }}
text value="Data loaded"
list separator=true
item name="First"
item name="Second"Compiles to JSX conditional rendering:
{!loading && (
<>
<span>Data loaded</span>
...
</>
)}State with expressions
The state node uses initial= for default values. Expression blocks allow non-string initializers:
state name=darkMode initial=false ← bare value (string)
state name=count initial={{ 0 }} ← expression (number)
state name=items initial={{ [] }} ← expression (empty array)
state name=config initial={{ { key: 1 } }} ← expression (object)Text with dynamic values
Text nodes render expressions directly into JSX:
text value="Static text" ← string literal
text value={{ count }} ← variable reference
text value={{ items.length + " results" }} ← concatenation
text value={{ isActive ? "On" : "Off" }} ← ternary
text bind=username ← bound to stateThe bind= prop on text nodes renders the state variable directly: {username}.