Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Livewire Wizard Laravel Package

spatie/laravel-livewire-wizard

Build multi-step Livewire wizards where each step is its own component, with easy navigation control and full access to regular Livewire features.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and make sure your app is on Livewire 3+:

composer require spatie/laravel-livewire-wizard

There is no config file or published assets to worry about. The package is headless: you get two base classes and a small runtime for step navigation and state sharing.

Start by creating one wizard component and at least two step components.

use Spatie\LivewireWizard\Components\WizardComponent;

class CheckoutWizardComponent extends WizardComponent
{
    public function steps(): array
    {
        return [
            CartStepComponent::class,
            DeliveryAddressStepComponent::class,
            ConfirmOrderStepComponent::class,
        ];
    }
}
use Spatie\LivewireWizard\Components\StepComponent;

class CartStepComponent extends StepComponent
{
    public function render()
    {
        return view('checkout.steps.cart');
    }
}

Render the wizard from any Blade page:

<livewire:checkout-wizard />

The first thing to build is a simple cart → address → confirm flow. Once that works, add validation, state sharing, and custom navigation. Look first at WizardComponent for lifecycle/navigation methods and StepComponent for step-side helpers; the demo app linked from the README is the fastest reference for a complete checkout flow.

Implementation Patterns

Linear flow with step-local buttons. Put navigation inside each step's Blade view:

<button wire:click="previousStep">Back</button>
<button wire:click="nextStep">Next</button>

Steps can call nextStep(), previousStep(), and showStep(SomeStep::class) directly. Keep navigation logic in the step or in a small parent view partial if you want consistent chrome.

Jump navigation and progress indicators. Use the wizard's step list to render a progress bar. Check membership with hasStep() before offering a link, and use showStep() to jump. This is useful for edit-from-summary flows where the user clicks "Edit address" on the confirmation step.

Share state deliberately. Each step exposes a state(): array containing the values other steps need. Read another step's state with forStepClass() or read everything with allStepState():

public function state(): array
{
    return ['email' => $this->email];
}

// in another step
$address = $this->state()->forStepClass(DeliveryAddressStepComponent::class);

Only include serializable values. Don't dump entire Eloquent models into state if a small DTO/array will do.

Guard transitions with validation. Override nextStep() in the step, validate, then call the parent:

public function nextStep()
{
    $this->validate();

    parent::nextStep();
}

This keeps validation close to the fields that own it and prevents users skipping required steps.

Dynamic step lists. Because steps() is a method, you can build the list conditionally from the authenticated user, cart contents, or feature flags. This is the main reason to prefer this package over a fixed form wizard. Guard downstream steps with hasStep() so a removed step doesn't break navigation.

Testing. The package exposes wizard testing helpers, and newer versions add StepComponent::testStep() for testing a step in isolation. Use these for navigation assertions and validation rules; fall back to plain Livewire component tests for the step's own rendering.

Integration with existing UI. Since the package is headless, wrap the wizard in your existing layout and use your own buttons, progress bar, and summary markup. If you need custom wrapper markup, override the wizard's render() or publish/override its view rather than fighting the default.

Gotchas and Tips

  • It is headless. There is no built-in Next/Back UI, progress bar, validation orchestration, or step-skipping guard. You implement those. Budget for that up front.
  • Wizard state is in-memory. A page refresh or a full Livewire reload starts over unless you persist state yourself (session, database, or a draft model). For long onboarding flows, persist after each step.
  • Validation errors disappear with the step. When you navigate away from a step, its component state and error bag go with it. Validate before navigating, and surface failures on the current step rather than trying to show errors from a previous step.
  • Multiple wizards per page need unique keys. This was fixed in 2.0.1, but if you're on an older version or nesting wizards, give each an explicit wire:key. Upgrade to at least 2.0.1.
  • Watch the major version boundary. 2.0 moved to Livewire 3, and 3.0 is the current line. If you're on Livewire 2, you need the 1.x line. Check the changelog before upgrading; don't assume a patch bump is safe across a Livewire major.
  • State serialization bites. Only public properties and serializable values survive Livewire requests. If you put a non-synthesizable object in state(), you'll get confusing hydration errors. 2.4.3 added support for some synthesizable objects, but arrays and scalars remain the safest choice.
  • Debugging navigation. If nextStep() appears to do nothing, check that the step class returned by steps() matches the class name you pass to showStep(), and inspect the wizard's current-step property in Livewire devtools. Class-string typos fail silently in navigation rather than throwing.
  • Don't reach into the wizard from arbitrary components. Navigation methods live on the wizard/step pair. From a parent page, use Livewire events or render the wizard as the interactive boundary instead of calling wizard internals.
  • Extension points are small. Override initialStep() to change the starting step, override render() for custom wizard chrome, and add methods on step components for anything domain-specific. Keep wizard-level logic thin; put business rules in step classes or services.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics