0

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

2
  • I see some people talk about missing comments (see here). Does that happen with you as well? Commented Jan 16, 2023 at 6:51
  • @Yinci Yes, the problem was being caused by the final wire:end HTML comment being missing. I eventually discovered that it was only happening when the dynamic component call was placed above the buttons that emit the event. I've added an answer accordingly. Commented Jan 16, 2023 at 9:11

2 Answers 2

0

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I assume this has to do with how Livewire is diffing the DOM. It's probably getting confused.
0

You are supposed to change it to this

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

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.