Unexpected Checkbox Behavior

I’m attempting to integrate Livewire into a project and have come across unexpected behavior with checkboxes. It seems that once the model for the checkboxes has been set, any item that was selected cannot be unselected. I feel like I’m missing something fundamental.

Here’s the setup:

app\Http\Livewire\CheckboxGroup.php

namespace App\Http\Livewire;

use Livewire\Component;

class CheckboxGroup extends Component
{
    public $items, $selected;

    public function mount()
    {
        $this->items = [
            ['id'=>1, 'name'=>'Item 1'],
            ['id'=>2, 'name'=>'Item 2'],
            ['id'=>3, 'name'=>'Item 3']
        ];
        $this->selected = [2];
    }

    public function render()
    {
        return view('livewire.checkbox-group');
    }
}

resources\views\livewire\checkbox-group.blade.php

<div>
    @foreach( $items as $item )
    <div>
        <label>
            <input type="checkbox"
                name="selected[]"
                value="{{ $item['id'] }}"
                wire:model='selected'>
            <span>{{ $item['name'] }}</span>
        </label>
    </div>
    @endforeach

    <div>
        @php var_dump($this->selected) @endphp
    </div>
</div>

And here’s the behavior I don’t understand

laravel-livewire-checkbox-behavior

Why isn’t Item 2 being cleared from the $selected array when I uncheck it? Why are the checkbox values integers when loaded from the mount() method (expected) and strings when I click the checkboxes?

If you made it here, thanks for taking the time and any help is really appreciated.

The value of a checkbox element is actually a DomString regardless of the type you provide it with. In your case you’re setting the checkbox value with the integer 2, however, that is converted to a DomString. So when you uncheck the checkbox, your component is actually trying to remove an element in your $selected array with the value "2" and not 2 as an integer.

The reason it gets rechecked, after being unchecked, if you select either option 1 or 3 is because the $selected array contains 2 and so Livewire does its thing when rerendering when it detects $selected has changed.