Content Binding
Content binding displays state and computed values in the DOM. Use data-bind for text content and data-bind-html for rich HTML, the two core attributes for rendering data to the page.
Text Binding
Use data-bind to display state values as text content, including nested object properties:
<div data-component="user-binding-demo">
<!-- Basic property binding -->
<div class="mb-3">
<h5 data-bind="name">Loading...</h5>
<p>Email: <span data-bind="email" class="text-primary"></span></p>
<p>Age: <span data-bind="age"></span> years old</p>
</div>
<!-- Nested property binding -->
<div class="mb-3">
<h6>Address Information:</h6>
<p><strong>City:</strong> <span data-bind="address.city"></span></p>
<p><strong>Country:</strong> <span data-bind="address.country"></span></p>
<p><strong>Theme:</strong> <span data-bind="settings.theme" class="badge bg-secondary"></span></p>
</div>
<!-- Interactive buttons to update data -->
<div class="mt-3">
<button class="btn btn-primary btn-sm me-2" data-action="updateUser">
Update User Info
</button>
<button class="btn btn-secondary btn-sm me-2" data-action="updateAddress">
Change Address
</button>
<button class="btn btn-info btn-sm" data-action="toggleTheme">
Toggle Theme
</button>
</div>
</div>
wildflower.component('user-binding-demo', {
state: {
name: 'John Doe',
email: 'john@example.com',
age: 30,
// Nested objects for dot notation binding
address: {
city: 'Springfield',
country: 'USA'
},
settings: {
theme: 'light'
}
},
updateUser() {
const users = [
{ name: 'Alice Smith', email: 'alice@test.com', age: 25 },
{ name: 'Bob Johnson', email: 'bob@test.com', age: 32 },
{ name: 'Carol Williams', email: 'carol@test.com', age: 28 },
{ name: 'David Brown', email: 'david@test.com', age: 35 }
]
const user = users[Math.floor(Math.random() * users.length)]
// Update all user properties in one call
Object.assign(this.state, user)
},
updateAddress() {
const cities = [
{ city: 'New York', country: 'USA' },
{ city: 'London', country: 'UK' },
{ city: 'Tokyo', country: 'Japan' },
{ city: 'Paris', country: 'France' }
]
const address = cities[Math.floor(Math.random() * cities.length)]
// Immutable update - creates new object for better performance
// This approach is recommended as it enables more efficient change detection
this.address = {
...this.address,
city: address.city,
country: address.country
}
},
toggleTheme() {
// Toggle nested property
this.settings.theme = this.settings.theme === 'light' ? 'dark' : 'light'
}
})
HTML Content Binding
data-bind-html renders raw HTML via innerHTML.
Never bind untrusted or user-supplied content without sanitization. Configure a sanitizer to prevent cross-site scripting (XSS) attacks:
// Using DOMPurify (recommended)
wildflower.setHtmlSanitizer(html => DOMPurify.sanitize(html));
In dev builds, a console warning appears when data-bind-html is used without a sanitizer configured.
Rendering Rich HTML
Use data-bind-html to render HTML content from state or computed properties:
<div data-component="html-binding-demo">
<!-- Direct HTML from state -->
<div class="mb-4">
<h5>Notification Message</h5>
<div data-bind-html="notification" class="alert alert-info"></div>
</div>
<!-- Computed HTML content -->
<div class="mb-4">
<h5>Status Display</h5>
<div data-bind-html="statusHtml" class="p-3 border rounded"></div>
</div>
<!-- Dynamic list rendered as HTML -->
<div class="mb-4">
<h5>Activity Log</h5>
<div data-bind-html="activityHtml" class="small"></div>
</div>
<div class="mt-3">
<button class="btn btn-success btn-sm me-2" data-action="addActivity">
Log Activity
</button>
<button class="btn btn-warning btn-sm me-2" data-action="toggleStatus">
Toggle Status
</button>
<button class="btn btn-danger btn-sm" data-action="clearLog">
Clear Log
</button>
</div>
</div>
wildflower.component('html-binding-demo', {
state: {
notification: '<strong>Welcome!</strong> Click buttons to see HTML binding in action.',
isOnline: true,
activities: [
{ time: '10:00', action: 'System started', type: 'info' }
]
},
computed: {
statusHtml() {
if (this.isOnline) {
return '<span class="text-success">●</span> <strong>Online</strong> - All systems operational'
}
return '<span class="text-danger">●</span> <strong>Offline</strong> - Connection lost'
},
activityHtml() {
if (this.activities.length === 0) {
return '<em class="text-muted">No activity yet</em>'
}
return this.activities.map(a =>
`<div class="border-bottom py-1">
<span class="text-muted">${a.time}</span> -
<span class="text-${a.type}">${a.action}</span>
</div>`
).join('')
}
},
addActivity() {
const actions = [
{ action: 'User logged in', type: 'success' },
{ action: 'Data synchronized', type: 'info' },
{ action: 'Settings updated', type: 'warning' },
{ action: 'Cache cleared', type: 'secondary' }
]
const random = actions[Math.floor(Math.random() * actions.length)]
const time = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })
this.activities.push({ time, ...random })
this.notification = `<strong>New:</strong> ${random.action} at ${time}`
},
toggleStatus() {
this.isOnline = !this.isOnline
this.notification = this.isOnline
? '<span class="text-success">✓</span> Connection restored'
: '<span class="text-danger">✗</span> Connection lost'
},
clearLog() {
this.activities = []
this.notification = '<em>Activity log cleared</em>'
}
})
How Content Binding Works
data-bind sets the element's textContent, so any HTML in the value is escaped and displayed as plain text. This is safe by default. Use dot notation for nested properties (e.g., data-bind="address.city").
data-bind-html sets the element's innerHTML, rendering actual HTML markup. Because this can execute scripts or inject malicious content, always configure a sanitizer in production:
wildflower.setHtmlSanitizer(html => DOMPurify.sanitize(html));
Both attributes react to state changes automatically. Only the specific elements bound to a changed property re-render. There is no full-page diffing.