Constela : Achieving React/Next.js-Level Expressiveness with Timers, Forms, Portals & More
Source: Dev.to
What is Constela?
Constela is a compiler‑first UI language optimized for AI‑generated interfaces. Instead of writing JavaScript, you describe UI behavior in a constrained JSON DSL that is validated, analyzed, and compiled into minimal runtime code. With the latest release, Constela reaches feature parity with React/Next.js for most common use cases.
Timer Actions
delay
Execute steps after a specified delay.
{
"name": "showNotification",
"steps": [
{
"do": "set",
"target": "notification",
"value": { "expr": "lit", "value": "Saved!" }
},
{
"do": "delay",
"ms": { "expr": "lit", "value": 3000 },
"then": [
{
"do": "set",
"target": "notification",
"value": { "expr": "lit", "value": "" }
}
]
}
]
}
interval
Execute an action repeatedly at a specified interval. The timer ID is stored in result.
{
"name": "startPolling",
"steps": [
{
"do": "interval",
"ms": { "expr": "lit", "value": 5000 },
"action": "fetchLatestData",
"result": "pollingTimerId"
}
]
}
clearTimer
Stop a running timer by its ID.
{
"name": "stopPolling",
"steps": [
{
"do": "clearTimer",
"target": { "expr": "state", "name": "pollingTimerId" }
}
]
}
Extended Event Data
Event handlers now have access to rich event data.
| Event Type | Available Variables |
|---|---|
| Input | value, checked |
| Keyboard | key, code, ctrlKey, shiftKey, altKey, metaKey |
| Mouse | clientX, clientY, pageX, pageY, button |
| Touch | touches (array of clientX, clientY, pageX, pageY) |
| Scroll | scrollTop, scrollLeft |
| File Input | files (array of name, size, type) |
Keyboard shortcut example
{
"onKeyDown": {
"event": "keydown",
"action": "handleShortcut",
"payload": {
"key": { "expr": "var", "name": "key" },
"isCtrl": { "expr": "var", "name": "ctrlKey" }
}
}
}
File input example
{
"kind": "element",
"tag": "input",
"props": {
"type": { "expr": "lit", "value": "file" },
"multiple": { "expr": "lit", "value": true },
"onChange": {
"event": "change",
"action": "handleFiles",
"payload": { "expr": "var", "name": "files" }
}
}
}
Form Features
Programmatic focus control
// Focus an element
{ "do": "focus", "target": { "expr": "ref", "name": "emailInput" }, "operation": "focus" }
// Select text
{ "do": "focus", "target": { "expr": "ref", "name": "codeInput" }, "operation": "select" }
// Blur (unfocus)
{ "do": "focus", "target": { "expr": "ref", "name": "searchInput" }, "operation": "blur" }
Validation state (HTML5 Constraint Validation API)
{
"kind": "element",
"tag": "input",
"ref": "emailInput",
"props": {
"type": { "expr": "lit", "value": "email" },
"required": { "expr": "lit", "value": true }
}
}
Display validation errors:
{
"kind": "if",
"condition": {
"expr": "not",
"operand": {
"expr": "validity",
"ref": "emailInput",
"property": "valid"
}
},
"then": {
"kind": "text",
"value": {
"expr": "validity",
"ref": "emailInput",
"property": "message"
}
}
}
Available validity properties
valid– overall validityvalueMissing– required field is emptytypeMismatch– type doesn’t match (email, url, etc.)patternMismatch– pattern doesn’t matchtooLong/tooShort– length constraint violationrangeUnderflow/rangeOverflow– range constraint violationmessage– browser’s validation message
Portal & Observer
Portal
Render content to a different location in the DOM (e.g., modals, tooltips).
{
"kind": "portal",
"target": "body",
"children": [
{
"kind": "element",
"tag": "div",
"props": { "className": { "expr": "lit", "value": "modal-overlay" } },
"children": [
{
"kind": "element",
"tag": "div",
"props": { "className": { "expr": "lit", "value": "modal-content" } },
"children": [ /* modal content */ ]
}
]
}
]
}
Target options
"body"–document.body"head"–document.head- Any CSS selector (e.g.,
"#modal-root")
IntersectionObserver (infinite scroll)
{
"kind": "element",
"tag": "div",
"ref": "sentinel",
"props": {
"onIntersect": {
"event": "intersect",
"action": "loadMoreItems",
"options": {
"threshold": 0.5,
"rootMargin": "100px"
}
}
}
}
Debounce & Throttle
Control how frequently an event handler runs.
Debounce (execute 300 ms after the last event)
{
"onInput": {
"event": "input",
"action": "search",
"debounce": 300
}
}
Throttle (execute at most once per 100 ms)
{
"onScroll": {
"event": "scroll",
"action": "trackScroll",
"throttle": 100
}
}
Common UI Patterns
| Pattern | Constela Feature |
|---|---|
| Auto‑hiding notifications | delay step |
| Real‑time data polling | interval + clearTimer |
| Keyboard shortcuts | Extended keyboard event data |
| File upload UI | files event data |
| Form validation | validity expression |
| Modal dialogs | portal node |
| Infinite scroll | intersect event |
| Search‑as‑you‑type | debounce option |
Getting Started
npm install @constela/start
mkdir -p src/routes
echo '{"version":"1.0","state":{},"actions":[],"view":{"kind":"element","tag":"div","children":[{"kind":"text","value":{"expr":"lit","value":"Hello Constela!"}}]}}' > src/routes/index.json
npx constela dev
Resources
- GitHub Repository: https://github.com/constela/constela
- Official Website: https://constela.dev