Specifications of Structive: A Framework That Makes State Management a Breeze
What is Structive? Structive is a framework built on single-file Web Components that offers a structure-driven template syntax designed to eliminate as much boilerplate and state-hook overhead as possible, while still providing a fully declarative UI and reactive state management. Learn more: – https://github.com/mogera551/Structive – https://github.com/mogera551/Structive-Example Entry Point Your entry point is an HTML file, and you’ll need to use an import map to alias your modules: { "imports": { "structive": "path/to/cdn/structive.js", "main": "./components/main.st.html" } } import { config, defineComponents } from "structive"; config.enableMainWrapper = false; config.enableShadowDom = false; config.enableRouter = false; defineComponents({ "app-main": "main" }); Script Register your components and tweak framework settings inside a block. Component Registration & Root Tag Use defineComponents to map your custom element tag names to their .st.html files. Then include the root component tag (here ) in your . Configuration Options Currently Structive does not ship with a built-in router or wrapper, so set: config.enableMainWrapper = false; config.enableRouter = false; config.enableShadowDom = false; // or true if you prefer Shadow DOM Roadmap Routing and automatic component-loading (“autoload”) support are coming soon. Components Each component lives in its own single file, with three sections: We’ll focus on the UI template and the state class. Structural Paths Both your template and your state class use structural paths to bind data. Paths use dot notation and support a wildcard * to represent array elements: Full path: user.profile.name Wildcard path: products.*.name In the template, * refers to the current item inside a for block. In your state class, you can also declare derived state getters using wildcards. UI Template Your can include: for blocks for iteration if blocks for conditional rendering Interpolation for embedding values Attribute binding for linking state to DOM properties, classes, attributes, and events You can also chain filters onto paths (e.g. |locale to format numbers). {{ for:products }} {{ products.*.name }} — {{ products.*.price|locale }} {{ endfor: }} {{ if:user.isLoggedIn }} Welcome, {{ user.profile.nickName }}! {{ else: }} Please log in. {{ endif: }} Enter your name: Click me for Block Start with {{ for:LIST_PATH }}, end with {{ endfor: }}. The path must resolve to an array. You don’t declare your own loop variable—inside, use structural paths. An implicit index variable $1 is provided; deeper loops get $2, $3, etc. {{ for:users }} {{ users.*.profile.name }} {{ endfor: }} {{ for:makers }} No: {{ $1|inc,1 }} Maker: {{ makers.*.name }} {{ for:makers.*.products }} Product No: {{ $2|inc,1 }} — {{ makers.*.products.name }} ({{ makers.*.products.*.price|locale }}) {{ endfor: }} {{ endfor: }} if Block Use {{ if:CONDITION_PATH }} … {{ endif: }}, with optional {{ else: }}. The path must return a boolean. You may apply filters, but not raw expressions. {{ if:user.isLoggedIn }} Hello, {{ user.profile.nickName }}! {{ else: }} Please log in. {{ endif: }} {{ if:user.age > 18 }} {{ if:user.age|gt,18 }} Interpolation Embed state values directly in text with {{ PATH }}. Filters can be chained. {{ user.profile.nickName }} {{ user.profile.nickName|uc }} {{ for:states }} {{ states.*.name }}, {{ states.*.population|locale }} {{ endfor: }} Attribute Binding Link state paths to DOM element properties, classes, attributes, and events—all via data-bind. Supports two-way binding for inputs. Property Binding Certain DOM props are auto two-way: value, checked, etc. {{ for:products }} {{ products.*.name }} {{ endfor: }} Conditional Class Binding Toggle a CSS class based on a boolean path. .adult { color: red; } Event Binding Map element events to methods on your state class. Use on-prefixed method names for clarity. Add Custom Attribute Binding Use attr. prefix when you need to set arbitrary HTML/SVG attributes. State Class Your state lives in a default-exported JS class. Define all your state as class properties. export default class { fruits = [ { name: "apple" }, { name: "banana" }, { name: "cherry" } ]; count = 0; user = { profile: { name: "Alice", age: 30 } }; } Event Handling Define methods on your class to handle events. Prefix them with on to distinguish them from utility methods. {{ count }} Increment

What is Structive?
Structive is a framework built on single-file Web Components that offers a structure-driven template syntax designed to eliminate as much boilerplate and state-hook overhead as possible, while still providing a fully declarative UI and reactive state management.
Learn more:
– https://github.com/mogera551/Structive
– https://github.com/mogera551/Structive-Example
Entry Point
Your entry point is an HTML file, and you’ll need to use an import map to alias your modules:
Script
Register your components and tweak framework settings inside a block.
Component Registration & Root Tag
Use defineComponents
to map your custom element tag names to their .st.html
files. Then include the root component tag (here
) in your .
Configuration Options
Currently Structive does not ship with a built-in router or wrapper, so set:
config.enableMainWrapper = false;
config.enableRouter = false;
config.enableShadowDom = false; // or true if you prefer Shadow DOM
Roadmap
Routing and automatic component-loading (“autoload”) support are coming soon.
Components
Each component lives in its own single file, with three sections:
We’ll focus on the UI template and the state class.
Structural Paths
Both your template and your state class use structural paths to bind data. Paths use dot notation and support a wildcard *
to represent array elements:
-
Full path:
user.profile.name
-
Wildcard path:
products.*.name
In the template, *
refers to the current item inside a for
block. In your state class, you can also declare derived state getters using wildcards.
UI Template
Your can include:
-
for
blocks for iteration -
if
blocks for conditional rendering - Interpolation for embedding values
- Attribute binding for linking state to DOM properties, classes, attributes, and events
You can also chain filters onto paths (e.g. |locale
to format numbers).
{{ for:products }}
{{ products.*.name }} — {{ products.*.price|locale }}
{{ endfor: }}
{{ if:user.isLoggedIn }}
Welcome, {{ user.profile.nickName }}!
{{ else: }}
Please log in.
{{ endif: }}
Enter your name:
type="text" data-bind="value:user.profile.name">
for
Block
Start with {{ for:LIST_PATH }}
, end with {{ endfor: }}
. The path must resolve to an array. You don’t declare your own loop variable—inside, use structural paths. An implicit index variable $1
is provided; deeper loops get $2
, $3
, etc.
{{ for:users }}
{{ users.*.profile.name }}
{{ endfor: }}
{{ for:makers }}
No: {{ $1|inc,1 }} Maker: {{ makers.*.name }}
{{ for:makers.*.products }}
Product No: {{ $2|inc,1 }} —
{{ makers.*.products.name }}
({{ makers.*.products.*.price|locale }})
{{ endfor: }}
{{ endfor: }}
if
Block
Use {{ if:CONDITION_PATH }}
… {{ endif: }}
, with optional {{ else: }}
. The path must return a boolean. You may apply filters, but not raw expressions.
{{ if:user.isLoggedIn }}
Hello, {{ user.profile.nickName }}!
{{ else: }}
Please log in.
{{ endif: }}
{{ if:user.age > 18 }}
{{ if:user.age|gt,18 }}
Interpolation
Embed state values directly in text with {{ PATH }}
. Filters can be chained.
{{ user.profile.nickName }}
{{ user.profile.nickName|uc }}
{{ for:states }}
{{ states.*.name }}, {{ states.*.population|locale }}
{{ endfor: }}
Attribute Binding
Link state paths to DOM element properties, classes, attributes, and events—all via data-bind
. Supports two-way binding for inputs.
Property Binding
Certain DOM props are auto two-way: value
, checked
, etc.
type="text" data-bind="value:user.profile.name">
{{ for:products }}
{{ products.*.name }}
type="text" data-bind="value:products.*.inventory">
{{ endfor: }}
Conditional Class Binding
Toggle a CSS class based on a boolean path.
.adult { color: red; }
data-bind="class.adult:user.isAdult">
Event Binding
Map element events to methods on your state class. Use on
-prefixed method names for clarity.
Custom Attribute Binding
Use attr.
prefix when you need to set arbitrary HTML/SVG attributes.
data-bind="attr.points:points">
State Class
Your state lives in a default-exported JS class. Define all your state as class properties.
Event Handling
Define methods on your class to handle events. Prefix them with on
to distinguish them from utility methods.
{{ count }}
export default class {
count = 0;
onIncrement() {
this.count++;
}
}
Inside a for
loop, handlers receive the index as a second argument:
{{ for:users }}
{{ users.*.name }}
{{ endfor: }}
export default class {
users = [
{ name: "Alice" },
{ name: "Bob" },
{ name: "Charlie" }
];
onClick(e, $1) {
alert("Clicked index = " + $1);
}
}
You can also update the looped item’s state by using a wildcard path:
{{ for:users }}
{{ users.*.name }}
{{ endfor: }}
export default class {
users = [
{ name: "Alice", selected: false },
{ name: "Bob", selected: false },
{ name: "Charlie", selected: false }
];
onToggle(e, $1) {
this["users.*.selected"] = !this["users.*.selected"];
}
}
Update Triggers
Any assignment to a class property via a structural path automatically re-renders the bound DOM. For arrays, use immutable methods (concat
, toSpliced
, etc.) rather than push
/pop
.
{{ count }}
{{ for:users }}
{{ users.*.name }}
{{ endfor: }}
export default class {
count = 0;
onIncrement() {
this.count += 1;
}
users = [
{ name: "Alice", selected: false },
{ name: "Bob", selected: false },
{ name: "Charlie", selected: false }
];
onDelete(e, $1) {
this.users = this.users.toSpliced($1, 1);
}
}
Derived State Creation
Use getters named with structural paths to compute derived values. Whenever their dependencies change, the UI updates automatically via dependency tracking.
{{ user.profile.name }}
{{ user.profile.ucName }}
type="text" data-bind="value:user.profile.name">
export default class {
user = {
profile: {
name: "Alice",
age: 30
}
};
get "user.profile.ucName"() {
return this["user.profile.name"].toUpperCase();
}
}
Derived Structural Paths with Wildcards
You can also create a wildcard-based derived state, as if each array element had a virtual property:
{{ for:users }}
{{ users.*.ucName }},
type="text" data-bind="value:users.*.name">
{{ endfor: }}
export default class {
users = [
{ name: "Alice", selected: false },
{ name: "Bob", selected: false },
{ name: "Charlie", selected: false }
];
get "users.*.ucName"() {
return this["users.*.name"].toUpperCase();
}
}
Summary of Development
- Use the same structural paths in your state class and UI template
- Perform all updates via structural paths
- Create derived state with getters named as paths
- Inside loops, use implicit indices (
$1
, $2
, …)
Finally
Any feedback or messages would be greatly appreciated!