Your First App

Build a counter app

Let's build a classic counter application to understand Constela's core concepts.

The Counter App

Here's the complete src/routes/counter.json for a counter:

json
{
  "version": "1.0",
  "route": {
    "path": "/counter"
  },
  "state": {
    "count": { "type": "number", "initial": 0 }
  },
  "actions": [
    {
      "name": "increment",
      "steps": [
        { "do": "update", "target": "count", "operation": "increment" }
      ]
    },
    {
      "name": "decrement",
      "steps": [
        { "do": "update", "target": "count", "operation": "decrement" }
      ]
    },
    {
      "name": "reset",
      "steps": [
        { "do": "set", "target": "count", "value": { "expr": "lit", "value": 0 } }
      ]
    }
  ],
  "view": {
    "kind": "element",
    "tag": "div",
    "children": [
      {
        "kind": "element",
        "tag": "h1",
        "children": [
          { "kind": "text", "value": { "expr": "lit", "value": "Counter" } }
        ]
      },
      {
        "kind": "element",
        "tag": "p",
        "children": [
          { "kind": "text", "value": { "expr": "lit", "value": "Count: " } },
          { "kind": "text", "value": { "expr": "state", "name": "count" } }
        ]
      },
      {
        "kind": "element",
        "tag": "div",
        "children": [
          {
            "kind": "element",
            "tag": "button",
            "props": { "onClick": { "event": "click", "action": "decrement" } },
            "children": [
              { "kind": "text", "value": { "expr": "lit", "value": "-" } }
            ]
          },
          {
            "kind": "element",
            "tag": "button",
            "props": { "onClick": { "event": "click", "action": "reset" } },
            "children": [
              { "kind": "text", "value": { "expr": "lit", "value": "Reset" } }
            ]
          },
          {
            "kind": "element",
            "tag": "button",
            "props": { "onClick": { "event": "click", "action": "increment" } },
            "children": [
              { "kind": "text", "value": { "expr": "lit", "value": "+" } }
            ]
          }
        ]
      }
    ]
  }
}

Understanding the Structure

Every Constela app has four main sections:

1. Version

json
{
  "version": "1.0"
}

The version field specifies which version of the Constela DSL you're using. This ensures compatibility as the language evolves.

2. State

json
{
  "state": {
    "count": { "type": "number", "initial": 0 }
  }
}

State defines the reactive data in your application. Each state field has:

  • A name (the key, e.g., "count")
  • A type ("number", "string", or "list")
  • An initial value

3. Actions

json
{
  "actions": [
    {
      "name": "increment",
      "steps": [
        { "do": "update", "target": "count", "operation": "increment" }
      ]
    }
  ]
}

Actions define how state changes. Each action has:

  • A name field to identify the action
  • An array of steps that execute sequentially

The do field specifies the step type:

  • "set" - Set a state value directly
  • "update" - Modify state with an operation (increment, decrement, push, pop, remove)
  • "fetch" - Make HTTP requests

4. View

json
{
  "view": {
    "kind": "element",
    "tag": "button",
    "props": { "onClick": { "event": "click", "action": "increment" } },
    "children": [...]
  }
}

View defines the UI structure. The kind field specifies the node type:

  • "element" - HTML element
  • "text" - Text content
  • "if" - Conditional rendering
  • "each" - List iteration
  • "component" - Reusable component
  • "slot" - Placeholder for children

Running the App

Save the JSON above as src/routes/counter.json in your Constela project, then start the development server:

bash
npm run dev

Open http://localhost:3000/counter to see your counter app in action.

What's Next?

Now that you understand the basics, explore: