Structive is a structure-driven template engine where structure itself defines meaning, logic, and data flow. Write structure, not syntax.
- Structure-Driven Rendering: Data paths like
list.*.valueautomatically bind to structure and scope. - Wildcard Path Access: Use
*to express repeated or nested structures naturally. - Scoped Getters with Declarative Logic: Define logic for each node in the structure with path-aware getters.
- Zero Boilerplate: No loops, no manual bindings — just structure.
- data-bind Attributes: Bind DOM element attributes directly to state using
data-bind="attr:path"syntax. - Lifecycle-Aware State: Hooks like
$connectedCallbackand$disconnectedCallbackon state class. - Component-Based with Single-File Components: HTML-like components with
<template>,<style>, and<script>sections. - Shadow DOM Optional: Use
static $config = { enableShadowRoot: false }to toggle.
- Define your import map in entry HTML:
<script type="importmap">
{
"imports": {
"@components/app-main": "path/to/main.st.html",
"@components/app-sub": "path/to/sub.st.html"
}
}
</script>Define your component's tag-name and file path on importmap.
- Load components using auto loader in entry HTML:
<script type="module" src="path/to/cdn/easyloder"></script>CDN Path of easyloader is https://cdn.jsdelivr.net/gh/mogera551/Structive@latest/dist/EasyLoaders/components.js.
- Use it in your HTML:
<app-main></app-main>
<app-sub></app-sub>Structive uses single-file components. Each component HTML file contains three sections:
<template>
<p>{{ message }}</p>
</template>
<style>
p {
color: steelblue;
}
</style>
<script type="module">
export default class {
message = "Hello, Structive!";
}
</script>- Order of sections is flexible, but
template → style → scriptis recommended. - The state class should be the default export and can define getters.
Structive is built on a simple but powerful idea: structure should define behavior.
{{ for:items }}
{{ items.*.label }}
{{ endfor: }}{{ if:user.isLoggedIn }}
Welcome!
{{ else: }}
Please log in.
{{ endif: }}get "list.*.selected"() {
return this.$1 === this.selectedIndex;
}You don't describe how to render. You describe the structure and let it render itself.
Learn more in docs/structure-philosophy.md
- Getting Started
- Template syntax
- data-bind Specification
- Wildcard Paths
- State Class and Getters
- $getAll and Dependency Tracking
- Single-File Components
- Lifecycle
- Structure Philosophy
<template>
<ul>
{{ for:list }}
<li>{{ list.*.double }}</li>
{{ endfor: }}
</ul>
</template>
<script type="module">
export default class {
list = [
{ value: 1 },
{ value: 2 },
{ value: 3 }
];
get "list.*.double"() {
return this["list.*.value"] * 2;
}
}
</script>This project is under active development. Feedback, thoughts, and contributions are welcome!
Share your thoughts on Zenn article... or open an issue right here.
MIT