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

RileyGWeb's avatar

Method only fires when clicking directly on the checkbox?

I have this here: (styling removed for brevity)

<ul>
    @foreach($mainTypes as $type)
        <li>
            <div wire:click="updateSelectedMainTypes('{{ $type }}')">
                <input name="mainType_{{ $type }}" id="mainType_{{ $type }}" type="checkbox">
                <label for="mainType_{{ $type }}">{{ $type }}</label>
            </div>
        </li>
    @endforeach
</ul>

The method in wire:click will fire if:

  1. I click directly in the checkbox
  2. I click within the div, but not on the label

It will fire, but it will not properly hydrate the component, if I:

  1. click on the label

For instance, updateSelectedMainTypes() adds whichever list item is clicked to an array, which I am outputting on the front-end. This array is not updated if the label is clicked on, but it is if either of the other two elements are. What in the world is going on? How could I debug this?

0 likes
3 replies
LaryAI's avatar
Level 58

It seems like the issue you're experiencing is related to the way Livewire handles the wire:click directive in combination with native browser events. When you click on the label, the browser naturally triggers the checkbox to change its state, but this might be interfering with Livewire's JavaScript handling of the wire:click event.

To ensure that the updateSelectedMainTypes method is called consistently, regardless of where you click within the div, you can modify your code to use Livewire's .stop modifier to stop the click event from propagating. Additionally, you should bind the checkbox's checked state to a Livewire model to ensure proper synchronization.

Here's how you can adjust your code:

<ul>
    @foreach($mainTypes as $type)
        <li>
            <div wire:click.stop="updateSelectedMainTypes('{{ $type }}')">
                <input wire:model="selectedMainTypes.{{ $type }}" name="mainType_{{ $type }}" id="mainType_{{ $type }}" type="checkbox">
                <label for="mainType_{{ $type }}">{{ $type }}</label>
            </div>
        </li>
    @endforeach
</ul>

In your Livewire component, you should have a property selectedMainTypes that keeps track of the selected types:

class YourComponent extends Component
{
    public $selectedMainTypes = [];

    public function updateSelectedMainTypes($type)
    {
        if (in_array($type, $this->selectedMainTypes)) {
            unset($this->selectedMainTypes[array_search($type, $this->selectedMainTypes)]);
        } else {
            $this->selectedMainTypes[] = $type;
        }
    }

    // ...
}

Make sure that $selectedMainTypes is properly initialized and that it reflects the state of the checkboxes.

By using wire:model, you're binding the checkbox state to the Livewire component's state, and by using wire:click.stop, you're ensuring that the click event does not propagate beyond the div element, which should make the behavior consistent regardless of where you click within the div.

If you still encounter issues, you can debug by adding wire:click to the label as well and see if that changes the behavior. You can also use browser developer tools to inspect the events and see if there are any JavaScript errors in the console when you click on different elements.

DanteB918's avatar

I have the following component / view going on in Livewire and am unable to replicate the issue, when clicking the label it is still adding to my array. Component:

<?php

namespace App\Livewire;

use Livewire\Component;

class TestComp extends Component
{
    public $mainTypes = ['type1', 'type2', 'type3'];

    public $chosenTypes = [];

    public function render()
    {
        return view('livewire.test-comp');
    }

    public function updateSelectedMainTypes($type) {
        if (! in_array($type, $this->chosenTypes)) {
            $this->chosenTypes[] = $type;
        }
    }
}

Blade:

<div>
    <ul>
        @foreach($mainTypes as $type)
            <li>
                <div wire:click="updateSelectedMainTypes('{{ $type }}')">
                    <input name="mainType_{{ $type }}" id="mainType_{{ $type }}" type="checkbox">
                    <label for="mainType_{{ $type }}">{{ $type }}</label>
                </div>
            </li>
        @endforeach
    </ul>

        @foreach ($chosenTypes as $type) 
            {{ $type }}
        @endforeach
</div>

Although, the common practice for livewire checkboxes is to wire the model to each input with a wire:key.

Commonly this would look like so:

Component:

<?php

namespace App\Livewire;

use Livewire\Component;

class TestComp extends Component
{
    public $mainTypes = ['type1', 'type2', 'type3'];

    public $chosenTypes = [];

    public function render()
    {
        return view('livewire.test-comp');
    }
}

Blade:

<div>
    <ul>
        @foreach($mainTypes as $type)
            <li>
                <div>
                    <input name="mainType_{{ $type }}" wire:model="chosenTypes" wire:key="{{ $loop->index }}" value="{{ $type }}" id="mainType_{{ $type }}" type="checkbox" />
                    <label for="mainType_{{ $type }}">{{ $type }}</label>
                </div>
            </li>
        @endforeach
    </ul>

        @foreach ($chosenTypes as $type) 
            {{ $type }}
        @endforeach
</div>

I hope this helps!

Snapey's avatar
  1. whenever you have a loop, you must use wire:key

  2. put wire:model on the checkbox. Dont use click

  3. wrap the input field in the label

Please or to participate in this conversation.