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

earmsby's avatar

Livewire component with datalist and modal

This is my third attempt to solve a challenge I am having with a livewire component.

First, here is an overview of what I need my component to do:

  • Show an input field which is linked to a datalist
  • The datalist is populated from a table in the database (accounts)
  • A button shows a modal form
  • The modal form allows the user to add a new table item (account)
  • When the modal is submitted, add the new account to the table and refresh the datalist to include the newest account & also then hide the modal again

I have three files to do this:

  1. The livewire component
  2. The livewire component blade
  3. The modal blade

Here is the modal:

<div id="modal">
    <div class="fixed inset-0 bg-gray-600 opacity-70"></div>

    <div class="bg-white shadow-md max-w-sm mx-auto mt-12 mb-12 rounded-md fixed inset-0">
        <div class="flex flex-col h-full justify-between">
            <header class="p-6">
                <h3 class="font-bold text-lg">
                    Modal Form
                </h3>
            </header>

            <main class="px-6 mb-4 overflow-auto">
                <form>
						[form fields here]
                </form>
            </main>

            <footer class="flex justify-end px-6 py-4 mt-6 bg-gray-200 rounded-b-md">
                <x-forms.button type="button" wire:click="hideModalPopUp()">Cancel</x-forms.button>
                <x-forms.button type="button" wire:click="createNewAccount()">Add The Account</x-forms.button>
            </footer>
        </div>
    </div>
</div>

This is the livewire blade that calls the modal:

<div>
    <x-forms.input
        name="selected-account"
        label="Find Account"
        list="accounts-list"
    />
    <datalist id="accounts-list">
        @foreach($accounts as $account)
            <option value="{{ $account->displayName }}"/>
        @endforeach
    </datalist>

    <x-forms.button
        type="button"
        class="mt-4"
        wire:click="showModalPopUp()"
    >
        {{ $buttonText }}
    </x-forms.button>

    @if($showModal)
        @include('modal_form')
    @endif
</div>

Note the conditional at the end that displays the modal if the value is set to true.

Finally, here is the component code:

Note that I'm logging the updated $this->accounts variable and it does include the newly added account.

The problem is that even though $this->hideModalPopUp() runs successfully (verified by logging) the modal stays visible and can't even be hidden by clicking the cancel button.

If I comment out the line that refreshes the list of accounts $this->accounts=Account::all()->sortBy('displayName'); then the modal functions normally but of course the accounts in the datalist do not include the newly added account.

I have been banging my head on this for several weeks. It seems like it should be a pretty straightforward thing but I just can not figure out how to resolve it. For the record I am not using any separate JS (Alpine or otherwise). The code above is pretty much it.

Appreciate any advice. Thanks!

0 likes
3 replies
LaryAI's avatar
Level 58

The issue you're experiencing is due to how Livewire handles public properties that are not simple types (like arrays or collections). When you assign a new collection to $this->accounts (with Account::all()->sortBy('displayName')), Livewire serializes and deserializes it between requests. This can cause unexpected re-rendering issues, especially when using collections, and can interfere with other properties (like $showModal) updating as expected.

The root cause:
When you assign a new collection to a public property, Livewire may not properly track changes to other properties in the same request cycle, causing the modal to remain open or not respond to state changes.


Solution

1. Use arrays, not collections, for Livewire public properties.
Convert the collection to an array before assigning to $this->accounts.

2. Update your component methods as follows:

3. Update your Blade to use the correct array keys:

If you use $account['displayName'] instead of $account->displayName in your Blade:

<datalist id="accounts-list">
    @foreach($accounts as $account)
        <option value="{{ $account['displayName'] }}"/>
    @endforeach
</datalist>

Summary

  • Always use arrays (not collections) for Livewire public properties.
  • Use ->toArray() when assigning Eloquent results to public properties.
  • Update your Blade to use array syntax.

This will resolve the modal not hiding and ensure your datalist updates as expected.


Extra tip:
If you want to keep using Eloquent collections internally, keep them as private/protected properties, and only expose arrays to the view.

Let me know if you need a more advanced example (e.g., with validation or dynamic form fields)!

earmsby's avatar

Unfortunately, that did not work. The modal still is stuck open after adding a new account. Anything else to try?

earmsby's avatar

Finally! I found a solution! I replaced:

@if($showModal)
        @include('modal_form')
@endif

with:

    <div wire:show="showModal">
        @include('modal_form')
    </div>

That seems to do the trick. The account is added to the data list and the modal is hidden.

Please or to participate in this conversation.