Frontend API Reference
Complete reference for all Alpine Gale magics, directives, and configuration APIs. Alpine Gale extends Alpine.js with server-driven capabilities through HTTP magics, directives, and reactive state management.
Gale v2.0 API Reference
Use $action() for HTTP requests with CSRF protection.
Add x-sync to components that need to send state to the server.
HTTP Magics
HTTP magics send requests to your server with automatic state serialization and SSE response handling.
Basic HTTP Methods
| Magic | Description |
|---|---|
$get(url, options?) |
Send GET request with state serialization |
$post(url, options?) |
Send POST request with state serialization |
$patch(url, options?) |
Send PATCH request with state serialization |
$put(url, options?) |
Send PUT request with state serialization |
$delete(url, options?) |
Send DELETE request with state serialization |
$action Magic (v2.0 - Recommended)
The primary magic for making HTTP requests with automatic CSRF protection. Defaults to POST and supports method chaining.
| Magic | Description |
|---|---|
$action(url, options?) |
POST request with CSRF protection (default) |
$action.get(url, options?) |
GET request |
$action.post(url, options?) |
POST request with CSRF protection (explicit) |
$action.put(url, options?) |
PUT request with CSRF protection |
$action.patch(url, options?) |
PATCH request with CSRF protection |
$action.delete(url, options?) |
DELETE request with CSRF protection |
Request Options
All HTTP magics accept an optional second parameter for request options.
// Request options object
{
include: ['email', 'name'], // Only send these state keys
exclude: ['password'], // Don't send these state keys
headers: { // Additional HTTP headers
'X-Custom': 'value'
},
retryInterval: 1000, // Initial retry interval (ms)
retryScaler: 2, // Exponential backoff multiplier
retryMaxWaitMs: 30000, // Max retry interval (ms)
retryMaxCount: 10, // Max retry attempts
requestCancellation: 'auto' // 'auto' | 'disabled' | AbortController
}
// Request options object
{
include: ['email', 'name'], // Only send these state keys
exclude: ['password'], // Don't send these state keys
headers: { // Additional HTTP headers
'X-Custom': 'value'
},
retryInterval: 1000, // Initial retry interval (ms)
retryScaler: 2, // Exponential backoff multiplier
retryMaxWaitMs: 30000, // Max retry interval (ms)
retryMaxCount: 10, // Max retry attempts
requestCancellation: 'auto' // 'auto' | 'disabled' | AbortController
}
| Option | Type | Default | Description |
|---|---|---|---|
include |
array | null |
Whitelist of state keys to send |
exclude |
array | null |
Blacklist of state keys to exclude |
headers |
object | {} |
Additional HTTP headers |
retryInterval |
number | 1000 |
Initial retry delay in milliseconds |
retryScaler |
number | 2 |
Multiplier for exponential backoff |
retryMaxWaitMs |
number | 30000 |
Maximum retry interval |
retryMaxCount |
number | 10 |
Maximum number of retry attempts |
requestCancellation |
string|AbortController | 'auto' |
Request cancellation strategy |
Navigation Magic
$navigate
Programmatic SPA navigation with state serialization.
<!-- Basic navigation -->
<button @click="$navigate('/dashboard')">Go to Dashboard</button>
<!-- With options -->
<button @click="$navigate('/search', { merge: true })">
Search (keep query params)
</button>
<!-- Replace history -->
<button @click="$navigate('/login', { replace: true })">
Login
</button>
| Option | Type | Description |
|---|---|---|
merge |
boolean | Keep current query params, override with new |
only |
array | Keep only these query params |
except |
array | Keep all except these query params |
replace |
boolean | Replace history instead of push |
key |
string | Navigation key for backend filtering |
Component Magics
$components
Access and manage named components registered with x-component.
| Method | Description |
|---|---|
$components.get(name) |
Get component data by name |
$components.getByTag(tag) |
Get all components with a specific tag |
$components.all() |
Get all registered components |
$components.has(name) |
Check if component exists |
$components.invoke(name, method, ...args) |
Invoke a method on a component |
Timing Solutions
| Method | Description |
|---|---|
$components.when(name, timeout?) |
Promise that resolves when component ready |
$components.onReady(names, callback) |
Callback when component(s) become ready |
Reactive State CRUD
| Method | Description |
|---|---|
$components.state(name, key?) |
Get reactive state proxy for a component |
$components.update(name, updates) |
Update component state (RFC 7386 merge patch) |
$components.create(name, state, options?) |
Initialize state on a component |
$components.delete(name, keys) |
Delete properties from component state |
$components.watch(name, keyOrCb, cb?) |
Watch component state for changes |
<!-- Display cart total reactively -->
<span x-text="$components.state('cart')?.total"></span>
<!-- Update cart from another component -->
<button @click="$components.update('cart', { total: 99.99 })">
Set Total
</button>
<!-- Wait for component to be ready -->
<div x-init="$components.when('cart').then(c => console.log('ready', c))"></div>
<!-- Watch for state changes -->
<div x-init="$components.watch('cart', 'items', (items) => console.log(items))"></div>
$invoke
Shorthand for invoking methods on named components.
<!-- Invoke method on named component -->
<button @click="$invoke('cart', 'recalculate', 2.5)">
Recalculate Cart
</button>
<!-- Equivalent to -->
<button @click="$components.invoke('cart', 'recalculate', 2.5)">
Recalculate Cart
</button>
File Magics
Magics for handling file uploads with the x-files directive.
| Magic | Returns | Description |
|---|---|---|
$file(name) |
object|null | Get info for a single file input |
$files(name) |
array | Get array of file info for multiple files |
$filePreview(name, index?) |
string | Get preview URL for a file |
$clearFiles(name?) |
void | Clear file input(s) |
$formatBytes(size, decimals?) |
string | Format bytes to human-readable string |
$uploading |
boolean | Whether upload is in progress |
$uploadProgress |
number | Upload progress (0-100) |
$uploadError |
string|null | Upload error message |
<div x-data>
<input type="file" x-files="avatar">
<!-- Show file info -->
<template x-if="$file('avatar')">
<div>
<img :src="$filePreview('avatar')">
<p x-text="$file('avatar').name"></p>
<p x-text="$formatBytes($file('avatar').size)"></p>
<button @click="$clearFiles('avatar')">Remove</button>
</div>
</template>
<!-- Upload progress -->
<div x-show="$uploading">
<progress :value="$uploadProgress" max="100"></progress>
</div>
</div>
<div x-data>
<input type="file" x-files="avatar">
<!-- Show file info -->
<template x-if="$file('avatar')">
<div>
<img :src="$filePreview('avatar')">
<p x-text="$file('avatar').name"></p>
<p x-text="$formatBytes($file('avatar').size)"></p>
<button @click="$clearFiles('avatar')">Remove</button>
</div>
</template>
<!-- Upload progress -->
<div x-show="$uploading">
<progress :value="$uploadProgress" max="100"></progress>
</div>
</div>
State Magics
$gale
Global connection state tracking.
| Property | Type | Description |
|---|---|---|
$gale.loading |
boolean | Whether any request is in progress |
$gale.error |
string|null | Current error message |
$gale.retrying |
boolean | Whether a retry is in progress |
$fetching
Per-element loading state. Returns true when the current component is making a request.
<div x-data>
<!-- Global loading state -->
<p x-show="$gale.loading">Loading...</p>
<p x-show="$gale.error" x-text="$gale.error"></p>
<!-- Per-component loading state -->
<p x-show="$fetching">This component is fetching...</p>
<button @click="$action('/save')" :disabled="$fetching">Save</button>
</div>
<div x-data>
<!-- Global loading state -->
<p x-show="$gale.loading">Loading...</p>
<p x-show="$gale.error" x-text="$gale.error"></p>
<!-- Per-component loading state -->
<p x-show="$fetching">This component is fetching...</p>
<button @click="$action('/save')" :disabled="$fetching">Save</button>
</div>
Directives
x-navigate
SPA navigation for links, forms, and container elements.
| Modifier | Description |
|---|---|
.merge |
Keep current query params |
.only.param1.param2 |
Keep only specified query params |
.except.param1 |
Keep all except specified params |
.replace |
Replace history instead of push |
.key.name |
Navigation key for backend filtering |
.debounce.300ms |
Debounce navigation |
.throttle.500ms |
Throttle navigation |
<!-- Basic link navigation -->
<a href="/dashboard" x-navigate>Dashboard</a>
<!-- Merge query params -->
<a href="/search?q=test" x-navigate.merge>Search</a>
<!-- Form navigation -->
<form action="/search" x-navigate.debounce.300ms>
<input name="q" type="text">
</form>
<!-- Container with inherited navigation -->
<nav x-navigate.key.sidebar>
<a href="/page1">Page 1</a>
<a href="/page2">Page 2</a>
</nav>
<!-- Skip navigation for specific links -->
<a href="/external" x-navigate-skip>External</a>
Dashboard SearchExternal
x-component
Register a named component for backend targeting and cross-component access.
<!-- Register a named component -->
<div x-data="{ total: 0 }" x-component="cart">
<span x-text="total"></span>
</div>
<!-- With tags -->
<div x-data="{ items: [] }"
x-component="cart"
data-tags="shopping,header">
...
</div>
...
x-files
Mark file inputs for automatic inclusion in requests.
| Modifier | Description |
|---|---|
.max-size-5mb |
Maximum file size validation |
.max-files-3 |
Maximum number of files |
<!-- Basic file input -->
<input type="file" x-files="avatar">
<!-- With validation -->
<input type="file" x-files="document" x-files.max-size-10mb>
<!-- Multiple files -->
<input type="file" multiple x-files="photos" x-files.max-files-5>
<!-- Handle file errors -->
<input type="file" x-files="avatar"
:file-error="alert($event.detail.message)">
:file-error="alert($event.detail.message)">
x-message
Display validation messages from the server.
<!-- Single field error -->
<input type="email" x-model="email">
<div x-message="email" class="text-red-500"></div>
<!-- Multiple fields -->
<div x-message="email,name"></div>
<!-- Single field error --> <input type="email" x-model="email"> <div x-message="email" class="text-red-500"></div> <!-- Multiple fields --> <div x-message="email,name"></div>
x-loading
Show/hide elements or modify attributes during loading.
| Modifier | Description |
|---|---|
| (none) | Show element during loading |
.remove |
Hide element during loading |
.class="classes" |
Add classes during loading |
.class.remove="classes" |
Remove classes during loading |
.attr="name" |
Add attribute during loading |
.delay |
Delay showing by 200ms |
.delay.500ms |
Custom delay duration |
<!-- Show spinner during loading -->
<span x-loading>Loading...</span>
<!-- Hide content during loading -->
<div x-loading.remove>Content</div>
<!-- Add opacity class -->
<button x-loading.class="opacity-50 cursor-wait">Submit</button>
<!-- Disable during loading -->
<button x-loading.attr="disabled">Submit</button>
<!-- Delay showing (avoid flicker) -->
<span x-loading.delay>Loading...</span>
Loading...ContentLoading...
x-indicator
Bind loading state to an Alpine property for programmatic control.
<div x-data="{ isLoading: false }" x-indicator="isLoading">
<!-- Use isLoading in any expression -->
<p x-show="isLoading">Loading...</p>
<button :disabled="isLoading">Submit</button>
<div :class="isLoading ? 'blur-sm' : ''">Content</div>
</div>
<div x-data="{ isLoading: false }" x-indicator="isLoading">
<!-- Use isLoading in any expression -->
<p x-show="isLoading">Loading...</p>
<button :disabled="isLoading">Submit</button>
<div :class="isLoading ? 'blur-sm' : ''">Content</div>
</div>
x-poll
Automatic polling with configurable intervals.
| Modifier | Description |
|---|---|
.5s |
Poll every 5 seconds |
.500ms |
Poll every 500 milliseconds |
.visible |
Only poll when element is visible |
.csrf |
Include CSRF token |
<!-- Poll every 5 seconds -->
<div x-data="{ stats: {} }" x-poll.5s="/api/stats">
<p x-text="JSON.stringify(stats)"></p>
</div>
<!-- Only poll when visible -->
<div x-poll.2s.visible="/api/updates"></div>
<!-- With CSRF token -->
<div x-poll.5s.csrf="/api/protected"></div>
<!-- Conditional stop -->
<div x-data="{ status: 'pending' }"
x-poll.2s="/api/status"
x-poll-stop="status === 'complete'">
</div>
<!-- Poll every 5 seconds -->
<div x-data="{ stats: {} }" x-poll.5s="/api/stats">
<p x-text="JSON.stringify(stats)"></p>
</div>
<!-- Only poll when visible -->
<div x-poll.2s.visible="/api/updates"></div>
<!-- With CSRF token -->
<div x-poll.5s.csrf="/api/protected"></div>
<!-- Conditional stop -->
<div x-data="{ status: 'pending' }"
x-poll.2s="/api/status"
x-poll-stop="status === 'complete'">
</div>
x-confirm
Show confirmation dialog before actions.
<!-- Static message -->
<button x-confirm="Are you sure?" @click="$action.delete('/item')">
Delete
</button>
<!-- Dynamic message -->
<button :x-confirm="`Delete ${name}?`" @click="$action.delete('/item')">
Delete
</button>
Configuration APIs
Alpine Gale exposes configuration APIs on the Alpine.gale object.
CSRF Configuration
// Configure CSRF settings
Alpine.gale.configureCsrf({
headerName: 'X-CSRF-TOKEN', // HTTP header name
metaName: 'csrf-token' // Meta tag name
});
// Get current configuration
const config = Alpine.gale.getCsrfConfig();
// Configure CSRF settings
Alpine.gale.configureCsrf({
headerName: 'X-CSRF-TOKEN', // HTTP header name
metaName: 'csrf-token' // Meta tag name
});
// Get current configuration
const config = Alpine.gale.getCsrfConfig();
Navigation Configuration
// Configure navigation
Alpine.gale.configureNavigation({
interceptLinks: true, // Intercept link clicks
interceptForms: true, // Intercept form submissions
updateHistory: true, // Update browser history
defaultMode: 'push' // 'push' | 'replace'
});
// Get current configuration
const config = Alpine.gale.getNavigationConfig();
// Configure navigation
Alpine.gale.configureNavigation({
interceptLinks: true, // Intercept link clicks
interceptForms: true, // Intercept form submissions
updateHistory: true, // Update browser history
defaultMode: 'push' // 'push' | 'replace'
});
// Get current configuration
const config = Alpine.gale.getNavigationConfig();
Message Configuration
// Configure message display
Alpine.gale.configureMessage({
stateKey: 'messages' // State property for messages
});
// Get current configuration
const config = Alpine.gale.getMessageConfig();
// Configure message display
Alpine.gale.configureMessage({
stateKey: 'messages' // State property for messages
});
// Get current configuration
const config = Alpine.gale.getMessageConfig();
Confirm Configuration
// Custom confirm handler (e.g., SweetAlert)
Alpine.gale.configureConfirm(async (message) => {
const result = await Swal.fire({
title: 'Confirm',
text: message,
showCancelButton: true
});
return result.isConfirmed;
});
// Get current configuration
const handler = Alpine.gale.getConfirmConfig();
// Custom confirm handler (e.g., SweetAlert)
Alpine.gale.configureConfirm(async (message) => {
const result = await Swal.fire({
title: 'Confirm',
text: message,
showCancelButton: true
});
return result.isConfirmed;
});
// Get current configuration
const handler = Alpine.gale.getConfirmConfig();
Component Registry APIs
// Manual component registration
Alpine.gale.registerComponent(element, 'cart', ['shopping']);
Alpine.gale.unregisterComponent('cart');
// Component access
Alpine.gale.getComponent('cart');
Alpine.gale.getComponentsByTag('shopping');
Alpine.gale.hasComponent('cart');
Alpine.gale.getAllComponents();
// State management
Alpine.gale.updateComponentState('cart', { total: 99 });
Alpine.gale.invokeComponentMethod('cart', 'recalculate', 2.5);
// Lifecycle hooks
Alpine.gale.onComponentRegistered(({ name }) => console.log('Registered:', name));
Alpine.gale.onComponentUnregistered(({ name }) => console.log('Unregistered:', name));
Alpine.gale.onComponentStateChanged(({ name, updates }) => console.log('Changed:', name));
// Timing solutions
Alpine.gale.whenComponentReady('cart').then(c => console.log(c));
Alpine.gale.onComponentReady('cart', c => console.log(c));
// Reactive CRUD
Alpine.gale.getComponentState('cart');
Alpine.gale.createComponentState('cart', { items: [] });
Alpine.gale.deleteComponentState('cart', 'discount');
Alpine.gale.watchComponentState('cart', 'total', (val) => console.log(val));
// Manual component registration
Alpine.gale.registerComponent(element, 'cart', ['shopping']);
Alpine.gale.unregisterComponent('cart');
// Component access
Alpine.gale.getComponent('cart');
Alpine.gale.getComponentsByTag('shopping');
Alpine.gale.hasComponent('cart');
Alpine.gale.getAllComponents();
// State management
Alpine.gale.updateComponentState('cart', { total: 99 });
Alpine.gale.invokeComponentMethod('cart', 'recalculate', 2.5);
// Lifecycle hooks
Alpine.gale.onComponentRegistered(({ name }) => console.log('Registered:', name));
Alpine.gale.onComponentUnregistered(({ name }) => console.log('Unregistered:', name));
Alpine.gale.onComponentStateChanged(({ name, updates }) => console.log('Changed:', name));
// Timing solutions
Alpine.gale.whenComponentReady('cart').then(c => console.log(c));
Alpine.gale.onComponentReady('cart', c => console.log(c));
// Reactive CRUD
Alpine.gale.getComponentState('cart');
Alpine.gale.createComponentState('cart', { items: [] });
Alpine.gale.deleteComponentState('cart', 'discount');
Alpine.gale.watchComponentState('cart', 'total', (val) => console.log(val));
SSE Event Protocol
Alpine Gale processes these Server-Sent Events from the backend.
| Event | Description |
|---|---|
gale-patch-state |
Update Alpine state (RFC 7386 merge patch) |
gale-patch-elements |
Update DOM elements (morph, replace, etc.) |
gale-patch-component |
Update named component state |
gale-invoke-method |
Invoke method on named component |