hyTags
HomeHome DocumentationDocumentation

Data Flow

Overview

Defining and referencing variables in HTML attributes can be verbose. This is why hyTags uses a stack-based model where commands pass data implicitly. Combined with type-based lookup and type-prefixed commands, stack-based code in hyTags is often quite concise and readable.

The Value Stack

When a command produces a result, it's pushed onto the stack. Subsequent commands read values based on their type. Values remain on the stack after being read, so the stack grows as commands execute:

<button>Calculate</button>
<on click>
  <number-new value="10">
  <!-- Stack: [10] -->
  <number-add value="5">
  <!-- Stack: [10, 15] -->
  <number-multiply value="2">
  <!-- Stack: [10, 15, 30] -->
  <debug-log>
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Values Stay on the Stack

Values are not removed when read. A value can be used by multiple commands:

<button>Use twice</button>
<on click>
  <number-new value="10">
  <!-- Stack: [10] -->
  <number-add value="5">
  <!-- Stack: [10, 15] -->
  <number-add value="3">
  <!-- Still uses 15, Stack: [10, 15, 18] -->
  <debug-log>
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Type-Based Lookup

Commands find values on the stack by type, searching from top to bottom (most recent first). Each value is used only once per command invocation. This allows values of different types to coexist:

<button>Show</button>
<on click>
  <string-new value="Result: ">
  <!-- Stack: ["Result: "] -->
  <number-new value="42">
  <!-- Stack: ["Result: ", 42] -->
  <number-to-string>
  <!-- Stack: ["Result: ", 42, "42"] -->
  <string-prepend>
  <!-- Finds "42" first, then "Result: " -->
  <!-- Stack: [..., "Result: 42"] -->
  <debug-log>
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Variables

Use variables to store values by name. Variables are set with var-set and retrieved with var-get:

<button>Use variable</button>
<on click>
  <var-set name="x" value="10" type="number"></var-set>
  <var-get name="x">
  <number-add value="5">
  <debug-log>
  <!-- Logs: 15 -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Updating Variables

Use var-update to modify a variable. The current value is passed to the commands block, and the result is stored back:

<button>Increment</button>
<on click>
  <var-set name="count" value="0" type="number"></var-set>
  <var-update name="count">
    <number-add value="1">
  </var-update>
  <var-update name="count">
    <number-add value="1">
  </var-update>
  <var-get name="count">
  <debug-log>
  <!-- Logs: 2 -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Variables as Parameters

Variables can be passed directly to command parameters using the $ prefix: $param="variable-name". This references the stored value without putting it on the stack:

<button>Add from variable</button>
<on click>
  <var-set name="amount" value="100" type="number"></var-set>
  <number-new value="50">
  <number-add $value="amount">
  <debug-log>
  <!-- Logs: 150 -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Value Scope

Use value-scope to run commands in an isolated stack. Values created inside the scope don't pollute the parent stack. This is useful when you need intermediate values that shouldn't remain on the stack:

Many commands with nested blocks use this same pattern: they define an inner stack and accept an optional return parameter. Examples include selection-scope, if-true, if-false, and style-animate.

<button>Isolated scope</button>
<on click>
  <number-new value="10">
  <!-- Stack: [10] -->
  <value-scope>
    <number-new value="5">
    <number-new value="3">
    <number-add>
    <!-- Inner stack: [5, 3, 8] -->
  </value-scope>
  <!-- Stack: [10] (inner values discarded) -->
  <debug-log>
  <!-- Logs: 10 -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

To pass a result back to the parent stack, use the return parameter to specify the type. The last value of that type in the inner stack is returned:

<button>Return from scope</button>
<on click>
  <number-new value="10">
  <!-- Stack: [10] -->
  <value-scope return="number">
    <number-new value="5">
    <number-add value="3">
    <!-- Inner stack: [5, 8] -->
  </value-scope>
  <!-- Stack: [10, 8] (8 returned) -->
  <number-add>
  <debug-log>
  <!-- Logs: 18 -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Required vs Optional Parameters

Commands have required and optional parameters. Required parameters without an explicit value are automatically read from the stack by type. Optional parameters without a value become null and are not read from the stack.

To read an optional parameter from the stack, use $param without a variable name. For example, number-to-string has an optional suffix parameter. Using $suffix reads the suffix from the stack:

<button>With suffix</button>
<on click>
  <string-new value=" items">
  <!-- Stack: [" items"] -->
  <number-new value="42">
  <!-- Stack: [" items", 42] -->
  <number-to-string $suffix>
  <!-- Reads suffix from stack -->
  <debug-log>
  <!-- Logs: "42 items" -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

If omitted, the parameter becomes null and is not read from the stack, even when a matching value is available:

<button>Without suffix</button>
<on click>
  <string-new value=" items">
  <!-- Stack: [" items"] -->
  <number-new value="42">
  <!-- Stack: [" items", 42] -->
  <number-to-string>
  <!-- suffix is null, string ignored -->
  <debug-log>
  <!-- Logs: "42" -->
</on>
👆 Try to change something! ⚠️ Preview only available on larger screens

Summary

  • Stack: Commands push results onto the stack. Values stay on the stack after being read.
  • Type lookup: Commands find the most recent value of the required type.
  • Variables: Named storage using var-set, var-get, and var-update.
  • value-scope: Isolated stack for intermediate values. Use return to pass a value back.
  • $param="variable-name": Reference a variable as a parameter value.
  • Required parameters: Read from stack by type when not provided.
  • Optional parameters: Become null when not provided (not read from stack).
Test succeeded Test failed