Skip to content

Datastar Attributes

This is the complete API reference for Datastar attributes used in Laravel Hyper. Datastar provides the reactive foundation that Hyper builds upon. All standard Datastar attributes work seamlessly in Hyper applications.

TIP

This reference covers standard Datastar attributes. For Hyper-specific extensions like data-error, data-for, data-if, and data-navigate, see Hyper Attributes.

Data Binding & Display

data-signals (Datastar)

Initializes reactive signals on an element. Signals are reactive variables that automatically update the UI when their values change.

Syntax:

blade
<div data-signals="{key: value, key2: value2}"></div>

Example:

blade
<div data-signals="{count: 0, name: 'John', items: [1, 2, 3]}">
    <!-- Signals available to all child elements -->
</div>

Hyper Enhancement

Hyper provides the @signals Blade directive for better Laravel integration. See Blade Directives.

data-bind (Datastar)

Creates two-way data binding between a form element and a signal. Changes in either direction sync automatically.

Syntax:

blade
<input data-bind="signalName" />

Modifiers:

  • __case.camel - Convert to camelCase
  • __case.kebab - Convert to kebab-case
  • __case.snake - Convert to snake_case
  • __case.pascal - Convert to PascalCase

Examples:

Text Input:

blade
<input type="text" data-bind="email" />

With Auto-Creation:

blade
<!-- Creates 'username' signal if it doesn't exist -->
<input data-bind="username" value="John" />

With Case Conversion:

blade
<input data-bind__case.snake="firstName" />
<!-- Binds to 'first_name' signal -->

Supported Elements:

  • <input> (text, number, email, password, etc.)
  • <textarea>
  • <select> (single and multiple)
  • <input type="checkbox">
  • <input type="radio">
  • <input type="file"> (base64 encoded)

data-text (Datastar)

Sets the text content of an element to a reactive expression. Automatically escapes HTML for XSS protection.

Syntax:

blade
<div data-text="expression"></div>

Examples:

Display Signal:

blade
<p data-text="$username"></p>

With Expression:

blade
<p data-text="'Hello, ' + $name + '!'"></p>
<p data-text="$count * 2"></p>
<p data-text="$price.toFixed(2)"></p>

Conditional Display:

blade
<p data-text="$items.length > 0 ? $items.length + ' items' : 'No items'"></p>

XSS Protection

data-text sets textContent, not innerHTML. HTML tags are automatically escaped and displayed as text.

data-html (Hyper)

Sets the HTML content of an element to a reactive expression. Unlike data-text, this renders HTML tags.

Syntax:

blade
<div data-html="expression"></div>

Examples:

Render HTML Content:

blade
<div data-html="$richContent"></div>

With Markdown Conversion:

blade
<div data-html="$markdownPreview" class="prose"></div>

Security

data-html renders content without escaping. Only use with trusted content. For user input, always sanitize on the server:

php
$safeHtml = strip_tags($userContent, '<p><strong><em><a>');

See Also: Display & Binding

data-cloak (Hyper)

Prevents Flash of Unstyled Content (FOUC) by hiding elements until Datastar initializes.

Syntax:

blade
<div data-cloak>
    <!-- Content hidden until framework loads -->
</div>

Setup Required:

css
[data-cloak] { display: none !important; }

Examples:

Hide Reactive Content:

blade
<div data-cloak data-signals="{show: true}">
    <div data-show="$show">
        Won't flash before framework initializes
    </div>
</div>

See Also: Display & Binding

data-attr:* (Datastar)

Sets HTML attributes dynamically based on reactive expressions. Replace * with any attribute name.

Syntax:

blade
<element data-attr:attributeName="expression"></element>

Examples:

Dynamic Links:

blade
<a data-attr:href="'/users/' + $userId">Profile</a>

Conditional Attributes:

blade
<button data-attr:disabled="$isProcessing">Submit</button>
<img data-attr:src="$avatar || '/default.jpg'" />

Data Attributes:

blade
<div data-attr:data-id="$todoId" data-attr:data-status="$status"></div>

Multiple Attributes:

blade
<input data-attr:placeholder="$placeholder"
       data-attr:maxlength="$maxLength"
       data-attr:required="$isRequired" />

Conditionals

data-show (Datastar)

Conditionally shows or hides an element using CSS display property. The element remains in the DOM.

Syntax:

blade
<div data-show="condition"></div>

Examples:

Basic Conditional:

blade
<div data-show="$isVisible">
    This content is conditionally visible
</div>

With Complex Logic:

blade
<div data-show="$user && $user.role === 'admin'">
    Admin-only content
</div>

Toggle Pattern:

blade
<div data-signals="{showDetails: false}">
    <button data-on:click="$showDetails = !$showDetails">Toggle</button>
    <div data-show="$showDetails">Details content...</div>
</div>

Performance

data-show keeps elements in the DOM (just hidden). For conditional rendering that removes elements from the DOM, use Hyper's data-if.

Events

data-on:* (Datastar)

Attaches event listeners to elements. Replace * with any valid DOM event name.

Syntax:

blade
<element data-on:eventName="expression"></element>

Available Modifiers:

  • __prevent - Calls preventDefault() on the event
  • __stop - Calls stopPropagation() on the event
  • __once - Listener fires only once
  • __passive - Passive event listener
  • __debounce.{time}ms - Debounce execution (with optional .leading or .trailing)
  • __throttle.{time}ms - Throttle execution (with optional .leading or .notrailing)
  • __window - Attach listener to window
  • __outside - Trigger when event is outside element
  • __viewtransition - Wrap in View Transition API

Examples:

Click Events:

blade
<button data-on:click="$count++">Increment</button>
<button data-on:click="$count = 0">Reset</button>

With preventDefault:

blade
<form data-on:submit__prevent="@postx('/submit')">
    <button type="submit">Submit</button>
</form>

Debounced Input:

blade
<input data-bind="search"
       data-on:input__debounce.300ms="@get('/search?q=' + $search)" />

Throttled Event:

blade
<div data-on:scroll__throttle.100ms="handleScroll()">
    Content...
</div>

Multiple Modifiers:

blade
<button data-on:click__once__prevent="handleAction()">
    One-time action
</button>

Window Events:

blade
<div data-on:resize__window__throttle.250ms="$width = window.innerWidth">
    Window width: <span data-text="$width"></span>
</div>

Outside Clicks:

blade
<div data-on:click__outside="$dropdownOpen = false">
    <div data-show="$dropdownOpen">Dropdown content</div>
</div>

Common Events:

  • data-on:click - Click events
  • data-on:input - Input change events
  • data-on:change - Change events
  • data-on:submit - Form submission
  • data-on:keydown / data-on:keyup - Keyboard events
  • data-on:focus / data-on:blur - Focus events
  • data-on:mouseenter / data-on:mouseleave - Mouse events

Key Modifiers (Hyper):

Filter keyboard events by specific keys:

blade
<input data-on:keydown__enter="@postx('/submit')" />
<input data-on:keydown__escape="$editing = false" />
<div data-on:keydown__window__arrow-up="$selectedIndex--"></div>
ModifierKey
__enterEnter/Return
__escapeEscape
__spaceSpacebar
__tabTab
__arrow-up, __arrow-down, __arrow-left, __arrow-rightArrow keys
__delete, __backspaceDelete/Backspace
__a - __z, __0 - __9Letter/number keys
__ctrl, __shift, __alt, __metaSystem modifier keys

See Also: Events - Key Modifiers

Styling

data-class:* (Datastar)

Conditionally adds or removes CSS classes based on reactive expressions.

Syntax:

blade
<!-- Single class -->
<div data-class:className="condition"></div>

<!-- Multiple classes (object syntax) -->
<div data-class="{className: condition, className2: condition2}"></div>

Examples:

Single Class:

blade
<div data-class:active="$isActive">
    Content
</div>

Multiple Classes:

blade
<div data-class="{
    'bg-green-500': $status === 'success',
    'bg-red-500': $status === 'error',
    'bg-blue-500': $status === 'info'
}">
    Status indicator
</div>

Toggle Classes:

blade
<button data-on:click="$expanded = !$expanded"
        data-class:rotate-180="$expanded">
    Expand ▼
</button>

Active Navigation:

blade
<a href="/dashboard"
   data-class:active="$currentPage === 'dashboard'">
    Dashboard
</a>

data-style:* (Datastar)

Sets inline CSS styles dynamically based on reactive expressions.

Syntax:

blade
<div data-style:propertyName="value"></div>

Examples:

Dynamic Colors:

blade
<div data-style:background-color="$theme === 'dark' ? '#000' : '#fff'">
    Content
</div>

Dynamic Dimensions:

blade
<div data-style:width="$progress + '%'"
     data-style:height="'20px'">
    Progress bar
</div>

Conditional Opacity:

blade
<div data-style:opacity="$isLoading ? '0.5' : '1'">
    Content
</div>

Animation

data-transition (Hyper)

Adds smooth animations when showing/hiding elements with data-show. Supports helper mode, class mode, and collapse mode.

Helper Mode (Style-based):

blade
<div data-show="$visible" data-transition>
    Fades and scales smoothly
</div>

Helper Modifiers:

  • __opacity - Opacity transition only
  • __scale - Scale transition only
  • __scale__[value] - Custom scale value (0-100)
  • __duration__[ms] - Duration in milliseconds
  • __delay__[ms] - Delay before starting
  • __origin__[position] - Transform origin
  • __in - Enter animation only
  • __out - Leave animation only

Class Mode (Tailwind CSS):

blade
<div data-show="$visible"
     data-transition:enter="transition ease-out duration-300"
     data-transition:enter-start="opacity-0 scale-90"
     data-transition:enter-end="opacity-100 scale-100"
     data-transition:leave="transition ease-in duration-200"
     data-transition:leave-start="opacity-100 scale-100"
     data-transition:leave-end="opacity-0 scale-90">
    Content
</div>

Collapse Mode (Height Animation):

blade
<div data-show="$expanded" data-transition__collapse>
    Smoothly expands/collapses by height
</div>

<!-- With options -->
<div data-show="$expanded" data-transition__collapse__duration__500__min__50>
    500ms duration, 50px minimum height
</div>

Collapse Modifiers:

  • __collapse - Enable collapse mode
  • __duration__[ms] - Animation duration (default: 250ms)
  • __min__[px] - Minimum collapsed height (default: 0)

See Also: Styling - Transitions

Advanced Attributes

data-computed:* (Datastar)

Creates a read-only computed signal that automatically recalculates when dependencies change.

Syntax:

blade
<div data-computed:signalName="expression"></div>

Examples:

Shopping Cart Total:

blade
<div data-signals="{items: [{price: 10, qty: 2}, {price: 5, qty: 3}]}"
     data-computed:total="$items.reduce((sum, item) => sum + (item.price * item.qty), 0)">

    <p data-text="'Total: $' + $total"></p>
</div>

Full Name:

blade
<div data-signals="{firstName: 'John', lastName: 'Doe'}"
     data-computed:names="$firstName + ' ' + $lastName">

    <h1 data-text="$names"></h1>
</div>

Filtered List:

blade
<div data-signals="{users: [...], searchTerm: ''}"
     data-computed:filteredUsers="$users.filter(u => u.name.includes($searchTerm))">

    <p data-text="$filteredUsers.length + ' results'"></p>
</div>

TIP

Computed signals are cached and only recalculate when their dependencies change, making them efficient for expensive operations.

data-effect (Datastar)

Executes an expression whenever signals in the expression change. Useful for side effects like logging, analytics, or DOM manipulation.

Syntax:

blade
<div data-effect="expression"></div>

Examples:

Console Logging:

blade
<div data-effect="console.log('Count changed:', $count)">
    <button data-on:click="$count++">Count: <span data-text="$count"></span></button>
</div>

Local Storage Sync:

blade
<div data-effect="localStorage.setItem('theme', $theme)">
    <select data-bind="theme">
        <option value="light">Light</option>
        <option value="dark">Dark</option>
    </select>
</div>

data-ref (Datastar)

Creates a reference to an element that can be accessed .

Syntax:

blade
<element data-ref="referenceName"></element>

Examples:

Focus Management:

blade
<div data-signals="{showModal: false}">
    <button data-on:click="$showModal = true; $modalInput.focus()">
        Open Modal
    </button>

    <div data-show="$showModal">
        <input data-ref="modalInput" />
    </div>
</div>

Scroll to Element:

blade
<button data-on:click="$section.scrollIntoView({ behavior: 'smooth' })" 
        class="p-2 bg-blue-500 text-white rounded">
    Scroll to Section
</button>

<div style="height: 1000px;"></div>

<div data-ref="section" class="p-5 bg-gray-200 rounded">
    Target section content
</div>

Element Measurements:

blade
<div data-ref="box"
     data-on:click="$width = $box.offsetWidth">
    <p data-text="'Width: ' + $width + 'px'"></p>
</div>

data-on-intersect (Datastar)

Triggers an expression when an element enters or exits the viewport using IntersectionObserver.

Syntax:

blade
<element data-on-intersect="expression"></element>

Modifiers:

  • __once - Trigger only once
  • __half - Trigger when 50% visible
  • __full - Trigger when 100% visible
  • __threshold.{0-1} - Custom visibility threshold
  • __rootMargin.{value} - Root margin (e.g., 100px)

Examples:

Lazy Loading:

blade
<img data-attr:src="$loaded ? $imageUrl : '/placeholder.jpg'"
     data-on-intersect__once="$loaded = true" />

Infinite Scroll:

blade
<div data-on-intersect__once="@get('/load-more?page=' + $page++)">
    Loading sentinel
</div>

Scroll Animations:

blade
<div data-on-intersect__half="$visible = true"
     data-class:fade-in="$visible">
    Animated content
</div>

View Tracking:

blade
<article data-on-intersect__once__half="gtag('event', 'article_viewed', {id: $articleId})">
    Article content
</article>

data-on-interval (Datastar)

Executes an expression repeatedly at specified intervals.

Syntax:

blade
<element data-on-interval="expression"></element>

Modifiers:

  • __duration.{time}ms - Set interval duration (default: 1000ms)
  • __leading - Execute immediately, then at intervals

Examples:

Auto-Refresh Dashboard:

blade
<div data-on-interval__duration.5000ms="@get('/dashboard/stats')">
    <!-- Stats that refresh every 5 seconds -->
</div>

Countdown Timer:

blade
<div data-signals="{timeLeft: 60}"
     data-on-interval__duration.1000ms="$timeLeft > 0 && $timeLeft--">
    <p data-text="'Time remaining: ' + $timeLeft + 's'"></p>
</div>

Clock:

blade
<div data-signals="{currentTime: new Date().toLocaleTimeString()}"
     data-on-interval__duration.1000ms="$currentTime = new Date().toLocaleTimeString()">
    <p data-text="$currentTime"></p>
</div>

data-resize (Hyper)

Executes an expression when an element's dimensions change using ResizeObserver.

Syntax:

blade
<div data-resize="expression"></div>

Expression receives width and height arguments.

Modifiers:

  • __document - Observe viewport instead of element
  • __debounce.[time] - Debounce resize events
  • __throttle.[time] - Throttle resize events

Examples:

Track Element Size:

blade
<div data-signals="{w: 0, h: 0}"
     data-resize="$w = width; $h = height">
    Size: <span data-text="$w"></span> x <span data-text="$h"></span>
</div>

Viewport Resize:

blade
<div data-resize__document="$isMobile = width < 768">
    <div data-show="$isMobile">Mobile view</div>
    <div data-show="!$isMobile">Desktop view</div>
</div>

See Also: Refs & Observers - Resize

data-teleport (Hyper)

Renders element content at a different DOM location while maintaining reactivity.

Syntax:

blade
<template data-teleport="selector">
    <!-- Content rendered at selector -->
</template>

Modifiers:

  • __prepend - Insert before target
  • __append - Insert after target

Examples:

Modal Pattern:

blade
<template data-teleport="body">
    <div data-show="$modalOpen" class="modal">
        Modal content rendered at body
    </div>
</template>

Prepend/Append:

blade
<template data-teleport__prepend="#target">
    Inserted before #target
</template>

<template data-teleport__append="#target">
    Inserted after #target
</template>

See Also: Teleport

data-persist (Hyper)

Automatically persists signal values to localStorage or sessionStorage.

Syntax:

blade
<div data-signals="{count: 0}" data-persist="count"></div>

Modifiers:

  • __session - Use sessionStorage instead of localStorage
  • __as.[key] - Custom storage key
  • __prefix.[name] - Add prefix to storage key

Examples:

Basic Persistence:

blade
<div data-signals="{theme: 'light', count: 0}" data-persist="theme, count">
    <!-- theme and count persist across page reloads -->
</div>

Session Storage:

blade
<div data-signals="{temp: ''}" data-persist__session="temp">
    <!-- Clears when browser closes -->
</div>

Custom Key:

blade
<div data-signals="{count: 0}" data-persist__as.mycounter="count">
    <!-- Stored as 'mycounter' instead of '_x_count' -->
</div>

See Also: Persistence

HTTP Actions

These actions make HTTP requests to your Laravel backend. They automatically send signals in the request and process SSE responses.

Hyper CSRF Protection

Hyper provides CSRF-protected versions: @postx, @putx, @patchx, @deletex. See Blade Directives.

@get(url, options) (Datastar)

Makes a GET request. Signals are sent as query parameters.

Syntax:

blade
<element data-on:event="@get('/endpoint', {options})"></element>

Examples:

Basic GET:

blade
<button data-on:click="@get('/api/data')">Load Data</button>

With Signal Parameters:

blade
<button data-on:click="@get('/search?q=' + $searchTerm)">Search</button>

With Options:

blade
<button data-on:click="@get('/data', {
    headers: {'X-Custom-Header': 'value'},
    openWhenHidden: true
})">Load</button>

@post(url, options) (Datastar)

Makes a POST request. Signals are sent in the request body as JSON.

Syntax:

blade
<element data-on:event="@post('/endpoint', {options})"></element>

Examples:

Basic POST:

blade
<form data-on:submit__prevent="@post('/api/submit')">
    <input data-bind="name" />
    <button type="submit">Submit</button>
</form>

CSRF Protection

Use @postx instead for CSRF-protected POST requests in Laravel:

blade
<button data-on:click="@postx('/create')">Create</button>

@put(url, options) (Datastar)

Makes a PUT request. Use @putx for CSRF protection.

Example:

blade
<button data-on:click="@putx('/api/update/' + $id)">Update</button>

@patch(url, options) (Datastar)

Makes a PATCH request. Use @patchx for CSRF protection.

Example:

blade
<button data-on:click="@patchx('/api/patch/' + $id)">Patch</button>

@delete(url, options) (Datastar)

Makes a DELETE request. Use @deletex for CSRF protection.

Example:

blade
<button data-on:click="@deletex('/api/delete/' + $id)">Delete</button>

Request Options

All HTTP actions accept an options object with these properties:

typescript
{
    // Request configuration
    contentType: 'json' | 'form',           // Default: 'json'
    headers: { [key: string]: string },     // Custom headers

    // Signal filtering
    filterSignals: {
        include: RegExp,                     // Include only matching signals
        exclude: RegExp                      // Exclude matching signals
    },

    // Advanced options
    selector: string,                        // Form selector for submission
    openWhenHidden: boolean,                 // Keep connection open in background
    requestCancellation: boolean             // Cancel concurrent requests (default: true)
}

Automatic Cancellation

Fetch requests automatically terminate when their initiating element is removed from the DOM. This prevents memory leaks and unnecessary network activity when components unmount.

Examples:

Filter Signals:

blade
<button data-on:click="@post('/submit', {
    filterSignals: {
        include: /^form\./,
        exclude: /^temp/
    }
})">Submit Form Data Only</button>

Custom Headers:

blade
<button data-on:click="@get('/api/data', {
    headers: {
        'X-API-Key': $apiKey,
        'X-Client-Version': '1.0'
    }
})">Load</button>

Form Content Type:

blade
<button data-on:click="@post('/upload', {
    contentType: 'form'
})">Upload</button>

Expression Context

All Datastar expressions have access to these special variables:

  • $signalName - Access any signal (prefix with $)
  • $$refs - Object containing all data-ref elements
  • $$signals - Object containing all signals (for debugging)
  • el - Current element (available in event handlers)
  • event - Event object (in event handlers)

Example:

blade
<div data-on:click="console.log('Element:', el, 'Event:', event, 'All signals:', $$signals)">
    Debug Click
</div>

Learn More