# VoltX Bindings
Bindings connect reactive state to the DOM using `data-volt-*` attributes. Each binding evaluates expressions and updates the DOM when dependencies change.
All bindings support the full expression syntax documented in [Expression Evaluation](./expressions), including property access, operators, function calls, and signal unwrapping.
## Content
### Text Content
The `data-volt-text` binding updates an element's text content:
```html
Fallback text
```
Text content is automatically escaped for security. Use this binding for any user-generated content to prevent XSS attacks.
The fallback text (between the opening and closing tags) is displayed until the framework mounts and evaluates the expression.
### HTML Content
The `data-volt-html` binding updates an element's innerHTML:
```html
```
This binding renders raw HTML without escaping. Only use it with trusted content. Never use `data-volt-html` with user-generated content unless it has been sanitized.
The binding removes existing children before inserting new content. Event listeners on removed elements are not automatically cleaned up—prefer using `data-volt-if` for conditional content with event handlers.
## Attributes
### Generic Attributes
The `data-volt-bind:*` syntax binds any HTML attribute:
```html
Link
```
The attribute name follows the colon. The expression value is converted to a string and set as the attribute value.
For boolean attributes (`disabled`, `checked`, `required`, etc.), the attribute is added when the expression is truthy and removed when falsy.
### Class Binding
The `data-volt-class` binding toggles CSS classes based on an object expression:
```html
```
Each key in the object is a class name. When the corresponding value is truthy, the class is added; when falsy, the class is removed.
Class names with hyphens or spaces must be quoted. The binding preserves existing classes not managed by VoltX.js.
## Event Bindings
### Event Listeners
The `data-volt-on-*` syntax attaches event listeners where the wildcard is the event name:
```html
```
The binding value is the URL. When the element is activated (clicked for buttons, submitted for forms), the request is sent.
### Target and Swap
Control where and how the response HTML is inserted using `data-volt-target` and `data-volt-swap`:
```html
```
**Target** is a CSS selector identifying the element to update. If omitted, the element with the HTTP binding is the target.
**Swap** strategies determine how content is inserted:
- `innerHTML`: Replace target's content (default)
- `outerHTML`: Replace target itself
- `beforebegin`: Insert before target
- `afterbegin`: Insert as target's first child
- `beforeend`: Insert as target's last child
- `afterend`: Insert after target
- `delete`: Remove target from DOM
- `none`: Make request but don't modify DOM
### Form Serialization
Forms with HTTP bindings automatically serialize input values:
```html
```
The framework serializes form data based on the HTTP method:
- GET/DELETE: Query parameters in URL
- POST/PUT/PATCH: Request body as `application/x-www-form-urlencoded` or `multipart/form-data` for file uploads
### Loading Indicators
Show loading states during requests with `data-volt-indicator`:
```html
Loading...
```
The indicator element (selected by CSS selector) has a `loading` class added during the request and removed when complete.
### Retry Logic
Enable automatic retry with exponential backoff using `data-volt-retry`:
```html
```
The binding value is the maximum number of retry attempts. The framework automatically retries failed requests with increasing delays (1s, 2s, 4s, etc.).
Retries only occur for network failures and 5xx server errors. Client errors (4xx) are not retried.
## Plugins
Plugins extend the framework with additional bindings. Register plugins before mounting to make their bindings available.
### Persist
The `data-volt-persist` binding synchronizes signals with browser storage:
```html
```
The binding syntax is `data-volt-persist:signalName="storageType"` where storage type is:
- `localStorage`: Persists across browser sessions
- `sessionStorage`: Persists for the current tab session
- `indexedDB`: For large datasets (async)
The signal value is serialized to JSON and stored. On mount, stored values override initial state.
### Scroll
Scroll bindings manage scroll position and behavior:
```html
```
**Scroll restore** saves scroll position before navigation and restores it when returning.
**Scroll to** scrolls the viewport to bring the target element into view when activated.
**Scroll spy** adds a class when the element enters the viewport and removes it when leaving.
**Smooth scrolling** enables CSS `scroll-behavior: smooth` for the element.
### URL Synchronization
The `data-volt-url` binding syncs signals with URL query parameters or hash:
```html
```
The binding syntax is `data-volt-url:signalName="urlPart"` where URL part is:
- `query`: Sync with query parameter (e.g., `?page=1`)
- `hash`: Sync with URL hash (e.g., `#section`)
- `history`: Sync with the full pathname + search (e.g., `data-volt-url:route="history:/app"`)
Signal changes update the URL, and URL changes (back/forward navigation) update signals. This enables client-side routing without additional libraries.
## Custom Bindings
Register custom bindings for domain-specific behavior using the plugin API:
```js
import { registerPlugin } from 'voltx.js';
// or: import { registerPlugin } from '@voltx/core';
registerPlugin('tooltip', (ctx) => {
const message = ctx.evaluate(ctx.element.getAttribute('data-volt-tooltip'));
const tooltip = document.createElement('div');
tooltip.className = 'tooltip';
tooltip.textContent = message;
ctx.element.addEventListener('mouseenter', () => {
document.body.appendChild(tooltip);
});
ctx.element.addEventListener('mouseleave', () => {
tooltip.remove();
});
ctx.addCleanup(() => tooltip.remove());
});
```
The plugin context provides:
- `element`: The DOM element with the binding
- `scope`: Signal scope for the mounted component
- `evaluate(expression)`: Evaluate expressions in the current scope
- `findSignal(path)`: Find signals by property path
- `addCleanup(fn)`: Register cleanup callbacks
Custom bindings should always register cleanup to prevent memory leaks.
## Lifecycle
All bindings follow a consistent lifecycle:
1. **Mount**: The `charge()` or `mount()` function discovers elements with `data-volt-*` attributes
2. **Evaluation**: Expressions are parsed and evaluated in the current scope
3. **Subscription**: Bindings subscribe to referenced signals
4. **Update**: When signals change, bindings re-evaluate and update the DOM
5. **Cleanup**: When unmounted, subscriptions are disposed and DOM changes are reverted
Cleanup is automatic for all built-in bindings. Custom bindings must explicitly register cleanup using `ctx.addCleanup()`.