Search code examples
laravel-livewire

Getting a "Multiple root elements detected." error in Livewire when there's only one root element


I'm trying to create a way to dynamically load Livewire nested components by having a main container component like this:

ComponentContainer.php

class ComponentContainer extends Component
{
    public $component = 'active';

    protected $listeners = [
        'switch'
    ];

    public function switch(string $component)
    {
        $this->component = $component;
    }

    public function render()
    {
        return view('livewire.component-container', [
            'component' => $this->component,
            'key' => random_int(PHP_INT_MIN, PHP_INT_MAX),
        ]);
    }
}

component-container.blade.php

<div>
    <h1>Component Container</h1>

    @livewire($component, key($key))

    <button wire:click="$emit('switch', 'active')">
        {{ __('Active') }}
    </button>

    <button wire:click="$emit('switch', 'expired')">
        {{ __('Expired') }}
    </button>

</div>

It's working insomuch as when I click "active" or "expired" it's loading one of these components:

Active.php

class Active extends Component
{
    public function render()
    {
        return view('livewire.active');
    }
}

active.blade.php

<div>
    active
</div>

Expired.php

class Expired extends Component
{
    public function render()
    {
        return view('livewire.expired');
    }
}

expired.blade.php

<div>
    expired
</div>

But I get the following error in the console log, and I don't understand why:

Livewire: Multiple root elements detected. This is not supported. See docs for more information https://laravel-livewire.com/docs/2.x/troubleshooting#root-element-issues <div wire:id=​"jdHgW7KzB3wWUCl7vMI4">​expired​​

Doesn't seem to make sense as it's clearly just one root element. Interestingly it doesn't do it on the first load, regardless of whether I set $component to active or expired


Solution

  • The error is being caused by the final HTML comment (wire:end) being missing. For some reason, this only happens if the buttons are placed after the dynamic component call....

    This displays the "multiple root elements detected" error

    <div>
        <h1>Component Container</h1>
    
        @livewire($component, key($key))
    
        <button wire:click="$emit('switch', 'active')">
            {{ __('Active') }}
        </button>
    
        <button wire:click="$emit('switch', 'expired')">
            {{ __('Expired') }}
        </button>
    
    </div>
    

    But this works fine...

    <div>
        <h1>Component Container</h1>
    
        <button wire:click="$emit('switch', 'active')">
            {{ __('Active') }}
        </button>
    
        <button wire:click="$emit('switch', 'expired')">
            {{ __('Expired') }}
        </button>
    
        @livewire($component, key($key))
    
    </div>
    

    I'm not sure if this is expected behaviour or if it's a bug, but this fixes the issue described.