Lips
A runtime, fine-grained reactive UI framework with an HTML-native template syntax. Import it and build — no build step required — or precompile your templates ahead of time for CSP-safe, parse-free startup.
A template compiles to a small IR (intermediate representation). The DOM is cloned from static skeletons, and each binding becomes its own effect over per-key signals — so a state change updates only what actually read it. No virtual DOM, no diffing, no dirty-checking.
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script type="module">
import Lips from 'https://cdn.jsdelivr.net/npm/@lipsjs/lips/+esm'
const lips = new Lips()
lips.root({
state: { count: 0 },
handler: {
increment(){ this.state.count++ }
},
default: `
<div>
<h2>Count: {state.count}</h2>
<button on-click(increment)>Increment</button>
</div>`
}, '#app')
</script>
</body>
</html>
Why Lips
- Zero build stepImport and go. Templates are plain strings compiled in the browser.
- Fine-grained reactivityPer-key signals. An update costs O(bindings that changed).
- HTML-native syntaxControl flow is element-shaped —
<if>,<for>,<switch>— not an attribute DSL. - Serializable componentsA template is a plain object; its compiled IR is JSON.
- Precompile & CSPCompile ahead of time and run with no
evalunder a strict CSP. - Hot-swapReplace a live component's template while preserving its state.
How it differs
Most frameworks re-run your component function and reconcile the result. Lips never re-runs a component. A binding is created once, subscribes to exactly the state keys it read, and is the only thing that runs when one of those keys changes.
<div>
<h1>{state.title}</h1>
<p>{state.body}</p>
</div>
Writing state.title runs one text-node update. The <p> is untouched — not compared, not
visited. There is nothing to memoize, and no dependency array to keep in sync.
Two ways to ship
| Runtime compile | Precompiled | |
|---|---|---|
| Import | @lipsjs/lips |
@lipsjs/lips/runtime |
| Size (gzip) | ~21 KB | ~13 KB |
| Build step | none | Vite/Rollup plugin, or precompile() |
| Templates | compiled in the browser | compiled to IR at build time |
| CSP | needs unsafe-eval |
runs under strict script-src |
Both run the same engine and render identical DOM. See Precompile & CSP.
Where to go next
- Getting started — install, first component, project layout
- Core concepts — components, reactivity, lifecycle
- Template syntax — the full syntax reference
- API reference — every public method and type
Browser support
Any browser with ES modules, Proxy, and <template> — Chrome, Firefox, Safari and Edge
(current versions). Lips ships as ESM only.