Turbo Laravel Documentation

repository·2.x·Indexed 21 days ago

https://github.com/hotwired-laravel/turbo-laravel

A package providing conventions and tools to integrate Hotwire (Turbo) into Laravel applications, inspired by the turbo-rails gem. It includes features for Turbo Stream broadcasting via Laravel Echo and Reverb, automated model broadcasting using the Broadcasts trait, and specialized response builders and Blade components for seamless Hotwire integration.

Tokens
30.4K
Snippets
120
Records
135
Agent score
70%

What's inside Turbo Laravel

  1. Handle Form Submission Flow and Redirects

    2.x

    Turbo intercepts form submissions as fetch requests. For non-GET submissions, the server must return a redirect response with a 303 See Other status code. Turbo follows this redirect and renders the resulting response.

    Laravel Integration: When TurboMiddleware is active, Laravel's redirect() helper automatically converts 302 redirects to 303 for Turbo requests, ensuring compatibility.

    Validation Errors: For validation errors, return a 422 Unprocessable Entity status with the form HTML. Turbo Laravel automatically handles redirecting to the appropriate form resource (e.g., mapping *.update to *.edit) when the form route exists.

  2. Support non-JavaScript users with @csrf directive

    2.x

    Although Turbo.js can automatically handle CSRF tokens via the csrf-token meta tag, it is a best practice to still include the @csrf Blade directive within your HTML forms. This ensures that forms remain functional for users who have JavaScript disabled, as the form will contain the necessary token for a standard synchronous POST request.

    <form action="{{ route('chirps.store') }}" method="post">
        @csrf
        <!-- ... -->
    </form>
  3. Handle Validation Responses in Turbo Frames

    2.x

    When using Turbo Frames, a standard Laravel "redirect back" on validation failure can cause forms to disappear if the form was injected into a page that doesn't initially render it. Turbo expects a non-200 HTTP status code (typically 422 Unprocessable Entity) containing the form and error messages in the response body, rather than a redirect.

    Turbo Laravel solves this via TurboMiddleware, which intercepts ValidationException. It attempts to guess the correct form-rendering route and performs an internal request to fetch the form with the correct status code.

    Automatic Route Guessing

    The middleware relies on Laravel's resource route naming conventions to guess the form's location:

    • .store $\rightarrow$ guesses .create (e.g., posts.comments.store $\rightarrow$ posts.comments.create)
    • .update $\rightarrow$ guesses .edit (e.g., comments.update $\rightarrow$ comments.edit)
    • .destroy $\rightarrow$ guesses .delete

    If the guessed route does not exist, the middleware falls back to Laravel's default "redirect back" behavior.

  4. Automatic Turbo Stream defaults based on Model state

    2.x

    When passing a model instance directly to turbo_stream($model), the helper automatically selects an action based on the model's recent state:

    • Created model: Returns an append action (can be overridden as the second argument).
    • Updated model: Returns a replace action (can be overridden as update).
    • Deleted/Trashed model: Returns a remove action.
    // Override default action for a newly created model
    return turbo_stream($comment, 'append');
  5. How Turbo Laravel works (HTML Over the Wire)

    2.x

    Turbo Laravel integrates Turbo technologies with Laravel to enable partial page updates and real-time interactions using the 'HTML Over the Wire' philosophy. Instead of sending JSON, the server sends HTML, allowing the server to handle rendering while keeping the client-side logic minimal. It relies on four core techniques:

    1. Turbo Drive: Accelerates navigation by intercepting links and forms, replacing the <body> without a full page reload.
    2. Turbo Frames: Scopes navigation to independent segments of a page using <turbo-frame> elements.
    3. Turbo Streams: Delivers partial page changes (append, prepend, replace, update, remove, before, after, refresh) via HTTP responses or WebSockets.
    4. Stimulus: A JavaScript framework for adding behavior to HTML via data-controller, data-action, and data-target attributes.
  6. Flash messages in Hotwire Native requests

    2.x

    When using InteractsWithHotwireNativeNavigation helpers, calling ->with() on the redirect response behaves differently depending on the client:

    • Web Browser: Flashes the message to the session as normal.
    • Hotwire Native: Appends the flash messages to the query string of the signal URL (e.g., /recede_historical_location?status=Success).

    This allows the native client to intercept the redirect, read the query parameters, and display native UI elements like toasts.

    return $this->recedeOrRedirectTo(route('trays.show', $tray))
        ->with('status', __('Tray created.'));
  7. How Turbo Drive works

    2.x

    Turbo Drive accelerates navigation by intercepting link clicks and form submissions and converting them into fetch requests. Instead of a full browser reload, Turbo replaces the <body> and merges the <head> of the new page. This allows the window, document, and <html> elements to persist, maintaining the JavaScript environment and providing SPA-like speed with server-rendered HTML.

    • Application Visits: Initiated by clicking a link or calling Turbo.visit(). An advance visit pushes a new entry to the browser history, while a replace visit modifies the current history entry.
    • Restoration Visits: Triggered by the browser's Back/Forward buttons. Turbo attempts to restore the page from its cache; if no cache is available, it fetches fresh content.
  8. How model partials and broadcasting work

    2.x

    When using Turbo Stream Model Broadcasts (an optional feature), the package attempts to automatically find the correct partial for a model.

    Requirements for Model Partials:

    • The partial should rely on a single variable passed to it, named after the model instance in camelCase (e.g., a Comment model expects a $comment variable).
    • The package uses the model's class basename to determine this variable name.

    Broadcasting Channel Naming: By default, you can use the model's Fully Qualified Class Name (FQCN) as the broadcasting channel authorization route with a wildcard. For a Comment model in App\Models\, the channel would be App.Models.Comment.{comment}.

  9. Automate Broadcasting with the $broadcasts Property

    2.x

    Instead of manually hooking into Eloquent events, you can automate broadcasting by defining a $broadcasts property on your model. This instructs the Broadcasts trait to automatically trigger broadcasts on model events (created, updated, deleted).

    Basic Usage

    Setting $broadcasts = true enables default broadcasting (e.g., append on creation).

    Advanced Configuration

    You can pass an array to $broadcasts to customize behavior:

    • insertsBy: Set to 'prepend' or 'append' to change how new models are handled.
    • stream: Set a custom name for the Turbo Stream tag.
    protected $broadcasts = [
        'insertsBy' => 'prepend',
        'stream' => 'my-comments',
    ];

    Targeting Specific Channels

    Use $broadcastsTo to define which channel(s) the broadcasts should be sent to. This can be a relationship name or an array of relationships:

    protected $broadcastsTo = 'post'; // Sends to the 'post' relationship's channel

    Alternatively, implement a broadcastsTo() method for more complex logic, returning a model, a Channel instance, or an array of them.

    class Comment extends Model
    {
        use Broadcasts;
    
        protected $broadcasts = [
            'insertsBy' => 'prepend',
        ];
    
        protected $broadcastsTo = 'post';
    
        public function post()
        {
            return $this->belongsTo(Post::class);
        }
    }
  10. Broadcast Page Refreshes

    2.x

    You can automatically trigger page refreshes for users listening to a model's channel when that model changes. This is useful for keeping a UI in sync with the current state of a resource.

    Using the $broadcastsRefreshes Property

    Set protected $broadcastsRefreshes = true; to trigger a refresh broadcast on all relevant events (created, updated, deleted).

    Targeting Refresh Channels

    Use protected $broadcastsRefreshesTo to specify which related model's channel should receive the refresh signal. This can be a relationship name or an array of relationships.

    protected $broadcastsRefreshes = true;
    protected $broadcastsRefreshesTo = ['post'];

    Alternatively, implement a broadcastsRefreshesTo() method to return a model, a channel name string, or a Channel instance.

    class Comment extends Model
    {
        use Broadcasts;
    
        protected $broadcastsRefreshes = true;
    
        public function broadcastsRefreshesTo()
        {
            return [$this->post];
        }
    }
  11. Configure Turbo page refresh methods

    2.x

    You can instruct Turbo to use different page refresh strategies using meta tags. While the default behavior is to replace the <body> content, Turbo 8+ supports 'morphing' the page to preserve state and improve perceived performance.

    In a standard HTML environment, use these meta tags:

    <meta name="turbo-refresh-method" content="morph">
    <meta name="turbo-refresh-scroll" content="preserve">

    Turbo Laravel Integration: To make this more developer-friendly and enable autocomplete, use the provided Blade component:

    <x-turbo::refreshes-with method="morph" scroll="preserve" />
    <x-turbo::refreshes-with method="morph" scroll="preserve" />