Introduction to WildflowerJS
Full reactivity using nothing but standard HTML and JavaScript. No proprietary syntax, no build step, no vendor lock-in.
Other frameworks require you to learn and commit to non-standard extensions: JSX, .vue single-file components, Svelte's $: labels, Angular's template compiler. WildflowerJS achieves the same reactive data binding, computed properties, conditional rendering, and list management using only data-* attributes and plain JavaScript. Things browsers already understand.
- Reactive state: mutate a property, the DOM updates automatically
- Declarative binding via native
data-*attributes:data-bind,data-show,data-list,data-model,data-action - Computed properties with automatic dependency tracking
- List rendering with keyed reconciliation and nested list support
- Components, routing, SSR, and stores: all in one zero-dependency bundle
- No build step required: add a
<script>tag and go
Quick Example
A reactive shopping cart in minimal code. Add, remove, adjust quantities - the total updates automatically:
<h4>Shopping Cart</h4>
<div data-component="cart">
<div class="list-group" data-list="items">
<template>
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-center">
<strong data-bind="name"></strong>
<span>$<span data-bind="(price * qty).toFixed(2)"></span></span>
</div>
<div class="d-flex align-items-center gap-2 mt-1">
<button class="btn btn-sm btn-secondary" data-action="decrement">−</button>
<span data-bind="qty" style="display:inline-block;width:1.5em;text-align:center"></span>
<button class="btn btn-sm btn-secondary" data-action="increment">+</button>
<button class="btn btn-sm btn-danger ms-auto" data-action="remove">×</button>
</div>
</div>
</template>
</div>
<p data-show="items.length === 0" class="text-muted">Your cart is empty</p>
<div class="mt-3 text-end" data-show="items.length > 0">
<strong>Total: $<span data-bind="total"></span></strong>
</div>
</div>
wildflower.component('cart', {
state: {
items: [
{ name: 'Wireless Headphones', price: 59.99, qty: 1 },
{ name: 'Phone Case', price: 19.99, qty: 2 }
]
},
computed: {
total() {
return this.items
.reduce((sum, i) => sum + i.price * i.qty, 0)
.toFixed(2)
}
},
increment(event, element, { index }) {
this.items[index].qty++
},
decrement(event, element, { index }) {
if (this.items[index].qty > 1)
this.items[index].qty--
},
remove(event, element, { index }) {
this.items.splice(index, 1)
}
})
Works With Any Library
No Virtual DOM means third-party libraries just work. Use them directly:
wildflower.component('sortable-list', {
state: {
items: [{ name: 'Task A' }, { name: 'Task B' }, { name: 'Task C' }]
},
init() {
new Sortable(this.element.querySelector('ul'), {
onEnd: (evt) => {
const item = this.items.splice(evt.oldIndex, 1)[0]
this.items.splice(evt.newIndex, 0, item)
}
})
}
})
No refs. No useEffect. No adapters. Just use the library.
Why Choose WildflowerJS?
Every other reactive framework asks you to adopt a proprietary authoring format. WildflowerJS doesn't. Your templates are valid HTML, your logic is plain JavaScript, and your skills transfer anywhere.
- No vendor lock-in: your markup works without the framework; remove WildflowerJS and you still have a valid HTML page
- Zero learning tax: if you know
data-*attributes and vanilla JS, you already know the API - No toolchain required: no CLI scaffolding, no transpilation, no bundler config to maintain
- Drop into existing pages: add reactivity to server-rendered HTML, CMS templates, or static sites without rewriting anything
- Full-featured: routing, SSR, stores, computed properties, and list reconciliation ship in a single file
data-* and data-wf-* attribute prefixes. Use exclusive data-wf-* mode to avoid conflicts with third-party libraries. Learn more
Ready to get started?
Follow our simple installation guide and start building your first WildflowerJS application in minutes.