Constela : Achieving React/Next.js-Level Expressiveness with Timers, Forms, Portals & More

Published: (January 17, 2026 at 09:52 PM EST)
3 min read
Source: Dev.to

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 TypeAvailable Variables
Inputvalue, checked
Keyboardkey, code, ctrlKey, shiftKey, altKey, metaKey
MouseclientX, clientY, pageX, pageY, button
Touchtouches (array of clientX, clientY, pageX, pageY)
ScrollscrollTop, scrollLeft
File Inputfiles (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 validity
  • valueMissing – required field is empty
  • typeMismatch – type doesn’t match (email, url, etc.)
  • patternMismatch – pattern doesn’t match
  • tooLong / tooShort – length constraint violation
  • rangeUnderflow / rangeOverflow – range constraint violation
  • message – 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

PatternConstela Feature
Auto‑hiding notificationsdelay step
Real‑time data pollinginterval + clearTimer
Keyboard shortcutsExtended keyboard event data
File upload UIfiles event data
Form validationvalidity expression
Modal dialogsportal node
Infinite scrollintersect event
Search‑as‑you‑typedebounce 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

Back to Blog

Related posts

Read more »

𝗗𝗲𝘀𝗶𝗴𝗻𝗲𝗱 𝗮 𝗣𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻‑𝗥𝗲𝗮𝗱𝘆 𝗠𝘂𝗹𝘁𝗶‑𝗥𝗲𝗴𝗶𝗼𝗻 𝗔𝗪𝗦 𝗔𝗿𝗰𝗵𝗶𝘁𝗲𝗰𝘁𝘂𝗿𝗲 𝗘𝗞𝗦 | 𝗖𝗜/𝗖𝗗 | 𝗖𝗮𝗻𝗮𝗿𝘆 𝗗𝗲𝗽𝗹𝗼𝘆𝗺𝗲𝗻𝘁𝘀 | 𝗗𝗥 𝗙𝗮𝗶𝗹𝗼𝘃𝗲𝗿

!Architecture Diagramhttps://dev-to-uploads.s3.amazonaws.com/uploads/articles/p20jqk5gukphtqbsnftb.gif I designed a production‑grade multi‑region AWS architectu...