emaia/laravel-hotwire

The complete Hotwire stack for Laravel — Turbo Drive, Turbo Streams, Stimulus controllers and Blade components out of the box.

Maintainers

Package info

github.com/emaia/laravel-hotwire

pkg:composer/emaia/laravel-hotwire

Fund package maintenance!

emaia

Statistics

Installs: 29

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.9.12 2026-04-30 02:41 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Laravel Hotwire

The complete Hotwire stack for Laravel — Turbo Drive, Turbo Streams, Stimulus controllers and Blade components out of the box.

Table of Contents

Requirements

Installation

composer require emaia/laravel-hotwire

Publish the configuration file (optional):

php artisan vendor:publish --tag=hotwire-config

Quick Start

The install command scaffolds the Hotwire setup in your Laravel application — JS entry points, Stimulus loader, Turbo imports and CSS custom variants:

php artisan hotwire:install

This will:

  1. Copy JS and CSS scaffolding to resources/
  2. Add @hotwired/stimulus, @hotwired/turbo and @emaia/stimulus-dynamic-loader to your package.json
  3. Show instructions for the next steps

Only the three core dependencies above are added at install time. Extra npm packages required by specific components (e.g. tippy.js, @emaia/sonner) are published on demand by hotwire:check once you actually use a component that depends on them.

Options:

# Overwrite existing files without prompting
php artisan hotwire:install --force

# Install only JS or CSS scaffolding
php artisan hotwire:install --only=js
php artisan hotwire:install --only=css

If a target file already exists and is identical, it is skipped. If it differs, the command asks for confirmation before overwriting (unless --force is used).

After installation, a good next step is:

  1. Browse the package docs in the terminal to see what is available
  2. Publish the Stimulus controllers you actually want to use
  3. Run hotwire:check to verify controllers and npm dependencies used by your views

Explore the Docs

You can browse the package docs directly in the terminal:

php artisan hotwire:docs

This opens an interactive search across all controllers and components. Type a name, category, or keyword to filter:

 ┌ Search controllers and components ───────────────────────────────┐
 │ form                                                              │
 ├───────────────────────────────────────────────────────────────────┤
 │   auto-save           [forms]    Automatically saves a form…      │
 │ › auto-submit         [forms]    Submits a form automatically…    │
 │   clean-query-params  [forms]    Strips empty fields from the…    │
 │   optimistic--form    [turbo]    Dispatches optimistic UI…        │
 └───────────────────────────────────────────────────────────────────┘

Read a specific controller or component directly:

php artisan hotwire:docs auto-submit
php artisan hotwire:docs turbo/progress
php artisan hotwire:docs modal --component

List everything with category and description:

php artisan hotwire:docs --list
php artisan hotwire:docs --list --controller
php artisan hotwire:docs --list --component

Turbo

This package includes emaia/laravel-hotwire-turbo as a dependency, providing full Turbo integration for Laravel:

  • Turbo Streams — fluent builder for append, prepend, replace, update, remove, morph, refresh and more
  • Turbo Frames<x-turbo::frame> Blade component with lazy loading support
  • DOM helpersdom_id() and dom_class() for consistent element identification
  • Request detectionwantsTurboStream() and wasFromTurboFrame() macros
  • Blade directives@turboNocache, @turboRefreshMethod('morph'), etc.
  • Testing utilitiesInteractsWithTurbo trait with assertTurboStream() assertions
// Example: return Turbo Streams
return turbo_stream()
    ->append('messages', view('messages.item', compact('message')))
    ->remove('modal');

See the full documentation at emaia/laravel-hotwire-turbo.

Blade Components

Component Blade Stimulus Identifier Docs
Modal <x-hwc::modal> modal readme
Confirm Dialog <x-hwc::confirm-dialog> confirm-dialog readme
Flash Container <x-hwc::flash-container> toaster readme
Flash Message <x-hwc::flash-message> toast readme
Loader <x-hwc::loader> readme
Optimistic <x-hwc::optimistic> readme
Scroll Progress <x-hwc::scroll-progress> scroll-progress readme
Timeago <x-hwc::timeago> timeago readme

Stimulus Controllers (standalone)

Stimulus controllers without an associated Blade component. Used directly via data-controller and data-action.

Controllers live flat at the top level (resources/js/controllers/<name>_controller.{js,ts}). Substrate folders (turbo/, optimistic/, dev/) group controllers tied to a specific technical layer and use Stimulus' -- separator in the identifier.

php artisan hotwire:controllers auto-select auto-submit turbo/progress

Publish Stimulus Controllers

Publish the controllers you want to use in your app so they can be discovered by the bundler (Vite).

Interactive — select which controllers to publish:

php artisan hotwire:controllers

By name — publish a specific controller:

php artisan hotwire:controllers auto-select

Substrate namespace — publish every controller under a substrate folder (turbo, optimistic, dev):

php artisan hotwire:controllers turbo

Multiple arguments — mix names and substrate namespaces:

php artisan hotwire:controllers modal turbo/progress auto-submit

All at once:

php artisan hotwire:controllers --all

List available controllers (with publish status):

php artisan hotwire:controllers --list

Update only controllers that are already published but differ from the package source:

php artisan hotwire:controllers --outdated

# Non-interactive — useful after composer update in CI or deploy scripts
php artisan hotwire:controllers --outdated --force

--outdated never installs controllers that haven't been published yet, and skips those that are already up to date.

Overwrite existing files:

php artisan hotwire:controllers auto-select --force

Top-level controllers are copied flat to resources/js/controllers/ (e.g. modalresources/js/controllers/modal_controller.js, identifier modal). Controllers under a substrate folder preserve that folder and use Stimulus' -- separator (e.g. turbo/progressresources/js/controllers/turbo/progress_controller.js, identifier turbo--progress). @emaia/stimulus-dynamic-loader discovers and loads them automatically via import.meta.glob.

If a controller already exists and is identical to the package version, the command reports it as up to date. If it differs, it asks for confirmation before overwriting.

Top-level controllers

Controller Identifier Dependencies Docs
Animated Number animated-number readme
Auto Save auto-save readme
Auto Resize auto-resize readme
Auto Select auto-select readme
Auto Submit auto-submit readme
Char Counter char-counter readme
Checkbox Select All checkbox-select-all readme
Clean Query Params clean-query-params readme
Clear Input clear-input readme
Copy To Clipboard copy-to-clipboard readme
Modal modal readme
GTM gtm readme
Hotkey hotkey readme
Input Mask input-mask maska readme
Lazy Image lazy-image readme
Money Input money-input readme
OEmbed oembed readme
Remote Form remote-form readme
Reset Files reset-files readme
Timeago timeago date-fns readme
Toast toast @emaia/sonner readme
Toaster toaster @emaia/sonner readme
Tooltip tooltip tippy.js readme
Unsaved Changes unsaved-changes readme

Turbo

Controllers tied to Turbo Drive / Turbo Frames.

Controller Identifier Dependencies Docs
Polling turbo--polling @hotwired/turbo readme
Progress turbo--progress @hotwired/turbo readme
View Transition turbo--view-transition readme

Optimistic

Controller Identifier Dependencies Docs
Dispatch optimistic--dispatch @hotwired/turbo readme
Form optimistic--form @hotwired/turbo readme
Link optimistic--link @hotwired/turbo readme

Dev

Controller Identifier Dependencies Docs
Log dev--log readme

Verify Your Setup

List components and their required controllers:

php artisan hotwire:components

Shows each Blade component, its tag, and the Stimulus controllers it depends on — with publish status for each.

Check controllers for components used in your views:

php artisan hotwire:check

Scans resources/views for Hotwire components, then verifies two things:

  1. Stimulus controllers — every controller required by a used component is published and up to date.
  2. npm dependencies — every external package imported by those controllers (e.g. @emaia/sonner, tippy.js) is declared in your package.json (dependencies or devDependencies).

Exits with code 1 if either has pending items (useful for CI).

Both the configured prefix (hwc by default) and the literal hotwire alias are recognized, so views like <x-hwc::flash-message /> and <x-hotwire::flash-message /> are detected equally.

# Auto-publish missing/outdated controllers AND add missing npm deps to devDependencies
php artisan hotwire:check --fix

# Also run the detected package manager install command after adding deps
php artisan hotwire:check --fix --install

# Scan a custom path
php artisan hotwire:check --path=resources/views/app

Example output:

  ✓  toaster  up to date  (used by <x-hwc::flash-container>)
  ✓  toast    up to date  (used by <x-hwc::flash-message>)

Required npm dependencies:
  ✓  @emaia/sonner ^2.1.0  (used by toaster, toast)
  ✗  tippy.js ^6.3.7       missing from package.json (used by tooltip)

In interactive mode, hotwire:check asks whether to run the detected package manager install command after adding dependencies. In non-interactive scripts, use --fix --install to run it automatically.

Configuration

// config/hotwire.php

return [
    'prefix' => 'hwc', // <x-hwc::modal>
];

Change prefix to use a different prefix for Blade components. E.g. 'prefix' => 'hotwire'<x-hotwire::modal>.

View Customization

To customize the HTML/Tailwind of the components:

php artisan vendor:publish --tag=hotwire-views

Views published to resources/views/vendor/hotwire/ will take precedence over the package defaults.

Extending the package

Laravel Hotwire uses a single registry as the source of truth for:

  • Blade components
  • Stimulus controllers
  • external npm dependencies
  • docs paths
  • public categories

When adding a new component or controller to this package, update the registry entry in src/Registry/catalog.php.

Example component entry:

'modal' => [
    'class' => \Emaia\LaravelHotwire\Components\Modal::class,
    'view' => 'hotwire::component-views.modal',
    'docs' => 'docs/components/modal.md',
    'category' => 'overlay',
    'controllers' => ['modal'],
],

Example controller entry:

'tooltip' => [
    'source' => 'resources/js/controllers/tooltip_controller.js',
    'docs' => 'docs/controllers/tooltip.md',
    'category' => 'utility',
    'npm' => ['tippy.js' => '^6.3.7'],
],

More details: docs/registry.md

Testing

composer test

Manual Installation

If you prefer to set things up manually instead of using hotwire:install, follow the steps below.

Project setup (using Vite)

// resources/js/app.js
import "./libs";

// resources/js/libs/index.js
import "./turbo";
import "./stimulus";
import "../controllers";

// resources/js/controllers/index.js
import {Stimulus} from "../libs/stimulus";
import {registerControllers} from "@emaia/stimulus-dynamic-loader";

const controllers = import.meta.glob("./**/*_controller.{js,ts}", {
    eager: false,
});

registerControllers(Stimulus, controllers);

Install the required js dependencies:

bun add @hotwired/stimulus @hotwired/turbo @emaia/stimulus-dynamic-loader

TailwindCSS (v4)

Add these settings to your CSS entrypoint resources/css/app.css:

@source '../../vendor/emaia/laravel-hotwire/resources/views/**/*.blade.php';
@custom-variant turbo-frame (turbo-frame[src] &);
@custom-variant modal ([data-modal-target="dialog"] &);
@custom-variant aria-busy (form[aria-busy="true"] &);
@custom-variant self-aria-busy (html[aria-busy="true"] &);
@custom-variant turbo-frame-aria-busy (turbo-frame[aria-busy="true"] &);

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Contributions are welcome via pull requests.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.