Phoebe.js is a lightweight, dependency-free JavaScript library that lets you add reactivity, bindings, and control structures to your HTML. Write plain HTML, add a few attributes, and your UI updates automatically when something changes - no build step required.
- Reactive state: Declare your state once, let Phoebe update the DOM automatically.
- Dynamic attributes: Toggle classes, styles, and attributes based on state.
- Two-way binding:
phoebe-bindkeeps inputs and state in sync. - Control structures:
<phoebe-if>for conditionals<phoebe-for>for loops<phoebe-with>for scoped variables<phoebe-timer>for repeated execution<phoebe-component>for reusable snippets
- Text templating:
<phoebe-text>allows you to format your variables for output.
<head>
<link href="./src/phoebe.css" rel="stylesheet">
</head>
<script type="module">
import Phoebe from './src/phoebe.js'
window.phoebe = Phoebe({
// define your variables and methods here
})
</script><!DOCTYPE html>
<head>
<link href="./src/phoebe.css" rel="stylesheet">
</head>
<input type="text" phoebe-bind="shopping.newItem" phoebe:style="`width: ${shopping.newItem.length+3}ch`" />
<button type="button" phoebe:disabled="shopping.newItem.length === 0" phoebe:onclick="shopping.addItem()">+</button>
<phoebe-if if="shopping.items.length === 0">
List is empty
</phoebe-if>
<ul>
<phoebe-for var="item" in="shopping.items" index="idx">
<li>
<phoebe-text>Item: ${item}</phoebe-text>
<button type="button" phoebe:onclick="shopping.removeItem(idx)">-</button>
</li>
</phoebe-for>
</ul>
<script type="module">
import Phoebe from './src/phoebe.js'
window.phoebe = Phoebe({
shopping: {
newItem: '',
addItem() {
this.items.push(this.newItem)
this.newItem = ''
},
removeItem(index) {
this.items.splice(index, 1)
},
items: ["Apples", "Bananas", "Tomatos"]
}
})
</script>Have a look at the Phoebe.js by example page.
Write phoebe attributes (e.g. phoebe:value) always as text literals (like this: phoebe:value="count * 100"). Never fill them via javascript with dynamic values (like untrusted user provided input). Otherwise your app may be subject to XSS attacks (script injection).
✅ DO THIS:
<progress phoebe:value="count * 100">
❌ NEVER DO THIS:
progressElement.setAttribute("phoebe:value", userInput)
| phoebe.js | alpine.js | |
|---|---|---|
| Status | experimental | stable |
| Size | ~10KiB | ~40KiB |
| Syntax | tags (<phoebe-if>, <phoebe-for>, <phoebe-text>, ...) and attributes (phoebe-bind, phoebe-class, phoebe-ref, ...). |
Purely attributes (x-if, x-for, x-text, ...), no new tags introduced. |
| Reactivity | Basic implementation | Advanced reactivity with dependency tracking. Updates are usually more efficient out of the box. |
| External Components | <phoebe-component src="..."> to load external HTML or <template> by ID. |
Out of scope. |
| Learning Curve | Familiar HTML with custom elements. Looks like declarative HTML templates. | Attribute-driven. More similar to Vue.js |
| Target Audience | Developers who need a basic utility to manipulate the DOM | Developers who are used to more advanced solutions (like Vue.js or Svelte) |
- Split code into modules, bundle with Rollup
- Smarter reactivity (fine-grained dependency tracking)
- Transition/animation hooks
