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

drmmarsunited's avatar

wire:submit.prevent still attempting to POST form

I'm just learning Livewire and have been following some screencasts doing some basic form handling. My component view that has the form looks like this:

<form wire:submit.prevent="register" class="space-y-6" action="#" method="POST">
                <div>
                    <label for="email" class="block text-sm font-medium text-gray-700"> Email address </label>
                    <div class="mt-1">
                        <input wire:model="email" id="email" name="email" type="email" autocomplete="email" required class="@error('email') border-red-500 @enderror appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                    </div>
                    @error('email') <div class="mt-1 text-red-500 text-sm">{{ $message }}</div> @enderror
                </div>

                <div>
                    <button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Register</button>
                </div>
            </form>

This component is trying to use the register function looks like this:

class Register extends Component
{
    public string $email = '';
    public string $password = '';
    public string $passwordConfirmation = '';

    public function updatedEmail() {
        $this->validate(['email' => 'unique:users']);
    }

    public function register(): Redirector|Application|RedirectResponse
    {
        $data = $this->validate([
            'email' => 'required|email|unique:users',
            'password' => 'required|min:6|max:20|same:passwordConfirmation',
            'passwordConfirmation' => 'required'
        ]);

        $user = User::create([
            'email' => $data['email'],
            'password' => Hash::make($data['password'])
        ]);

        auth()->login($user);

        return redirect('/');
    }

    public function render()
    {
        return view('livewire.auth.register');
    }
}

Finally I'm using the normal app.blade.php layout file in the default location, and my web.php routes look like this:

Route::get('/', function () {
    return view('welcome');
});

Route::get('/register', Register::class);

According to Livewire docs (https://laravel-livewire.com/docs/2.x/rendering-components#page-components) for full page components, I'm passing everything through correctly to the slot in the app layout. So just in case here is the layout view as well (in resources/views/layouts/app.blade.php):

<html>

<head>
    @vite('resources/css/app.css')
    @livewireStyles
</head>

<body>
    {{ $slot }}

    @livewireScripts
</body>

</html>

I feel like I must be missing something really dumb or simple here that would explain why the form submit prevention isn't working and actually ending up doing the POST. Anyone have any pointers or been through this?

Thank you!

0 likes
19 replies
Snapey's avatar

check your browser developer tools.

In the network tab make sure everything is loaded ok

in the console make sure there are no errors

Type Livewire in the console and check the browser knows what you are talking about

How are you determining it's not working correctly since your code redirects anyway?

drmmarsunited's avatar

@Snapey Thanks for the reply. No obvious errors in the console or in the network trace, except for the failed POST as I don't have a POST route setup in routes, so since the POST is actually happening I'm expecting this failure.

However, when I type Livewire into the console, I get a reference error:

ReferenceError: Can't find variable: Livewire

When I inspect the elements, I see the Livewire Styles area and the Livewire Scripts areas, but I'm not sure if anything is missing in there or not in terms of structure.

drmmarsunited's avatar

I tested livewire from the error page, like an idiot sorry. I tested from the app page and now its working and getting a valid response. Still having the form issues though.

drmmarsunited's avatar

@Snapey And I guess I never answered your last question. I know my code isn't working because I end up on an error/debug page with a title of:

The POST method is not supported for this route. Supported methods: GET, HEAD.

Snapey's avatar

do you only have a single root element in your view?

drmmarsunited's avatar

@Snapey Only a single root div in my livewire component and the layout itself is pasted above in my original post. Here is the whole component for reference:

<div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8">
    <div class="sm:mx-auto sm:w-full sm:max-w-md">
        <img class="mx-auto h-32 w-auto" src="img/o2.png" alt="Oxygen Logo">
    </div>

    <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
        <div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
            <form wire:submit.prevent="register" class="space-y-6" action="#" method="POST">
                <div>
                    <label for="email" class="block text-sm font-medium text-gray-700"> Email address </label>
                    <div class="mt-1">
                        <input wire:model="email" id="email" name="email" type="email" autocomplete="email" required class="@error('email') border-red-500 @enderror appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                    </div>
                    @error('email') <div class="mt-1 text-red-500 text-sm">{{ $message }}</div> @enderror
                </div>

                <div>
                    <label for="password" class="block text-sm font-medium text-gray-700"> Password </label>
                    <div class="mt-1">
                        <input wire:model.lazy="password" id="password" name="password" type="password" autocomplete="current-password" required class="@error('password') border-red-500 @enderror appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                    </div>
                    @error('password') <div class="mt-1 text-red-500 text-sm">{{ $message }}</div> @enderror
                </div>

                <div>
                    <label for="passwordConfirmation" class="block text-sm font-medium text-gray-700"> Password Confirmation </label>
                    <div class="mt-1">
                        <input wire:model.lazy="passwordConfirmation" id="passwordConfirmation" name="passwordConfirmation" type="password" autocomplete="current-password" required class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
                    </div>
                </div>

                <div>
                    <button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Register</button>
                </div>
            </form>

            <p class="mt-2 text-center text-sm text-gray-600">
                <a href="/login" class="font-medium text-indigo-600 hover:text-indigo-500"> Already have an account? </a>
            </p>
        </div>
    </div>
</div>
RayC's avatar

Try changing the Route to post:

Route::post('/register', Register::class);

Also, I think you need to have the component wrapped in a div.

<div>
// The rest of your component here
</div>
drmmarsunited's avatar

@RayC The livewire docs don't state that I need have a post route at all, just a get route. Also, the submit.prevent directive should prevent the form from doing the actual POST. Also my component does have a root div. I just tried wrapping it in a vanilla div, but its doing the same thing.

drmmarsunited's avatar

@rayc By the way, I'm trying everything you're suggesting. I added a POST route to the same component, but now I get a 419 Expired error instead of the invalid method error. The screencast I'm following doesn't have a POST route or any extra root div either. Super confusing on my end. Appreciate the help!

RayC's avatar

@drmmarsunited You don't need the Route for livewire. But the error you received is due to it trying to post to the get Route. Posted that to show the reason for the cannot POST error.

Is there another component on the same page?

RayC's avatar

@drmmarsunited the 419 is more than likely due to not have the @csrf in the form. But I don't believe you need it with livewire, only when posting normally.

RayC's avatar

I don't think it will make a difference, but try changing the register() method to submit() and calling that inside your form. Maybe there is a name conflict.

 wire:submit.prevent="submit"
RayC's avatar

@drmmarsunited At a lose for you. Looking at your setup, there shouldn't be an issue.

Maybe remove the method="POST", I don't use it with livewire forms I submit. One of mine below. Don't think it matters, just throwing ideas your way.

<form class="form" action="#" id="dl_modal_daily_activity_form" wire:submit.prevent="submit">
drmmarsunited's avatar

@RayC I hadn't tried that before. It doesn't get me to an error page, but it changes the URL by adding query parameters to it:

?email=mitch%40test.com&password=xxxxx&passwordConfirmation=xxxxx#

It also doesn't seem to process any of my form validation before taking the action of loading the new URL. The email address field is supposed to be doing some real time validation which doesn't look to be working. Nor are the password length validations, etc

RayC's avatar

@drmmarsunited Seems like livewire isn't catching the submit by the form. Maybe a conflict with another library that is installed and being used on the page.

I'm fairly new to livewire myself, these possibilities I am throwing out might be nothing, but figured they'd be worth a try.

drmmarsunited's avatar
drmmarsunited
OP
Best Answer
Level 1

I have no idea what the root cause of this was. I even tried removing/reinstalling Livewire in this project.

I started a whole new project, generated all the components again from scratch and then brought over the same old code from the first project and everything started working without any issues. No idea what happened.

Thanks to @snapey and @rayc for the pointers in what to look for!

HasanAftab's avatar

@snapey I am facing the similar error now, my form submissions were working perfectly fine for 3 months but now all of a sudden, wire: submit has stopped working in all of my components.

If I try wire:click on button then it does trigger that action but wire:submit doesnt event trigger.

    <form wire:submit="sendNewEmailVerification" class="flex flex-col">
        <button type="submit" >
            Submit
        </button>
    </form>
1 like
frankhosaka's avatar

I believe the original code does not account for all the component properties in Blade, so I created a simplified version and had no issues. However, I couldn't use unique:user in the validation. I have the User model, but the table name in MySQL is tbusuarios. The component and Blade look like this:

<?php  // Teste.php
namespace App\Livewire;
use Livewire\Component;

class Teste extends Component {
    public $email;
    function register() { 
        $data = $this->validate(['email' => 'required|email|unique:tbusuarios']);
        dd("creating a user with email $this->email");
    }
}
blade
<form wire:submit.prevent="register" class="w-25">
    <div class="h-5"></div>
    <flux:input wire:model="email" />
    <div class="h-5"></div>
    <flux:button type="submit">Register</flux:button>
    <div class="h-5"></div>
    @error('email'){{ $message }}@enderror
</form>

Please or to participate in this conversation.