Describe loops, conditions, and state directly in HTML while JavaScript only mutates data. No DOM APIs. No JSX. No build step.
<!-- 1. Include HTTL-S from CDN --> <script src="https://cdn.jsdelivr.net/gh/KTBsomen/httl-s@main/statejs.js"></script> <!-- 2. HTML declares how state renders --> <p>Count: <state-element stateId="counter"> <template stateId="counter"> <span>{{clickCount}}</span> </template> </state-element> </p> <button onclick="clickCount++">+ Increment</button> <button onclick="clickCount = 0">Reset</button> <!-- 3. JavaScript: watch a variable, re-render on change --> <script> watch('clickCount', (name, value) => { setState({ stateId: 'counter', showloader: false }); }, 0); initState(); </script>
Three simple concepts — that's the entire mental model.
Use custom elements like <for-loop> and <condition-block>
to describe how data should render.
Just change your variables normally. Arrays, objects, primitives — plain JS, nothing special.
Call setState() to explicitly trigger DOM updates. No hidden magic, no virtual DOM.
Everything you need for dynamic HTML — nothing you don't.
${feat.desc}
Honest positioning — no overpromises.
The right tool for the right job.
Three steps. Zero config. Start building in under a minute.
<script src="https://cdn.jsdelivr.net/gh/KTBsomen/httl-s@main/statejs.js"></script>
watch('myVar', (name, value) => { setState({ loops: true, conditions: true }); }, initialValue);
initState();
The complete API — intentionally small.
| Function | Description | Example |
|---|
${api.name}${api.example}Declarative building blocks for your templates.
| Element | Purpose | Key Attribute |
|---|
${el.tag}${el.attr}Edit the HTML on the left — see it render live on the right.
Click Run to see output.
The honest comparison — use what fits your project.
| Feature | HTTL-S | Alpine.js | Vue (CDN) | React |
|---|