Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Unsociable's avatar

Livewire Form - What's the best way?

Hey! So I have a little side project I am going to explore and wondering what others would do.

I have a form, this form can have a lot of questions. I plan to split these questions into sections. I want the user to be able to go back at any time to a section and carry on. The user will not be having an account. I want to try to keep it as simple as possible for the user. I also plan on having back and next buttons to move between the sections.

So, I am thinking of the following:

Create a set of models, a Section Model, which has many Questions, then this will have a type (Radio, Input etc), then there will be a Questions Option model for the types such as select or radio.

Using alpine and livewire, I plan on a single component with the form, splitting the types up and displaying as needed. I would then save the current section to a data variable on the livewire controller, let's call this data. So it would be like:

$data['section1id']['question1id']['answer']

What would you do to handle this? Would you use some kinda of session ID to store this entry and allow users to come back?

0 likes
1 reply
LaryAI's avatar
Level 58

To handle a multi-step form with Livewire and Alpine.js, where users can navigate between sections and their progress is saved without requiring an account, you can follow these steps:

  1. Model Setup:

    • Create models for Section, Question, and QuestionOption.
    • Define relationships between them.
  2. Livewire Component:

    • Create a Livewire component to manage the form state and handle user interactions.
    • Use Alpine.js for front-end interactivity.
  3. Session Storage:

    • Use Laravel's session to store the user's progress so they can return to the form later.

Here's a step-by-step implementation:

Step 1: Model Setup

Step 2: Livewire Component

Step 3: Blade View

<!-- resources/views/livewire/multi-step-form.blade.php -->
<div x-data="{ currentSectionIndex: @entangle('currentSectionIndex') }">
    <form wire:submit.prevent="nextSection">
        <div x-show="currentSectionIndex === {{ $currentSectionIndex }}">
            <h2>{{ $currentSection->name }}</h2>
            @foreach($currentSection->questions as $question)
                <div>
                    <label>{{ $question->text }}</label>
                    @if($question->type === 'radio')
                        @foreach($question->options as $option)
                            <input type="radio" wire:model="data.{{ $currentSection->id }}.{{ $question->id }}" value="{{ $option->id }}">
                            {{ $option->text }}
                        @endforeach
                    @elseif($question->type === 'input')
                        <input type="text" wire:model="data.{{ $currentSection->id }}.{{ $question->id }}">
                    @endif
                </div>
            @endforeach
        </div>

        <div>
            <button type="button" x-show="currentSectionIndex > 0" wire:click="previousSection">Back</button>
            <button type="submit" x-show="currentSectionIndex < {{ count($sections) - 1 }}">Next</button>
            <button type="submit" x-show="currentSectionIndex === {{ count($sections) - 1 }}">Submit</button>
        </div>
    </form>
</div>

Step 4: Handling Form Submission

In your Livewire component, you can add a method to handle the final form submission:

public function submit()
{
    // Handle form submission, e.g., save to database
    // Clear session data
    Session::forget('form_data');
    // Redirect or show a success message
}

Summary

This setup allows you to:

  • Split the form into sections.
  • Navigate between sections using Alpine.js and Livewire.
  • Save the user's progress in the session so they can return to the form later.

This approach keeps the user experience simple and doesn't require user accounts.

Please or to participate in this conversation.