-
-
Notifications
You must be signed in to change notification settings - Fork 394
Description
Background
I’m trying to build a very simple Accordion Live Component that takes two content blocks - one for the collapsed state and one for the expanded state - and toggles between them.
I’m running into the limitation mentioned in the Live Component documentation:
Passing content via blocks to Live components works completely the same way you would pass content to Twig Components. Except with one important difference: when a component is re-rendered, any variables defined only in the "outside" template will not be available.
I’d like to confirm whether my understanding is correct and, if it is, whether there is a recommended pattern or if this is something that could be improved.
Minimal example
Accordion usage
{# any_file.html.twig #}
<twig:Accordion>
<twig:block name="collapsed">
Content to be shown when the accordion is collapsed.
</twig:block>
<twig:block name="expanded">
Content to be shown when the accordion is expanded.
</twig:block>
</twig:Accordion>Accordion implementation
{# Accordion.html.twig #}
<div {{ attributes }}>
{% if isCollapsed %}
{{ block('collapsed') }}
<button {{ live_action('expand') }}>Expand</button>
{% else %}
{{ block('expanded') }}
<button {{ live_action('collapse') }}>Collapse</button>
{% endif %}
</div>// Accordion.php
#[AsLiveComponent]
class Accordion
{
use DefaultActionTrait;
public bool $isCollapsed = true;
#[LiveAction]
public function expand(): void
{
$this->isCollapsed = false;
}
#[LiveAction]
public function collapse(): void
{
$this->isCollapsed = true;
}
}Problematic use case: Nested live components
Now imagine the Accordion is used inside another component that defines some data:
{# OuterComponent.html.twig #}
<div {{ attributes }}>
{# Nesting another live component: #}
<twig:Accordion>
<twig:block name="collapsed">
{{ someData }}
</twig:block>
<twig:block name="expanded">
{{ someData }}
</twig:block>
</twig:Accordion>
</div>// OuterComponent.php
#[AsLiveComponent]
class OuterComponent
{
use DefaultActionTrait;
#[LiveProp]
public string $someData;
}The initial rendering works, but any re-render results in an error message like Variable "someData" does not exist in OuterComponent.html.twig.
Expectations
I would like to...
- ... let the outer component own the data
- ... let the inner
Accordioncomponent own only the toggling behaviour - ... pass the content via blocks in a way that continues to work on re-renders
Work-around
So far, I only got this to work with a custom accordion_controller.js Stimulus controller that takes care of expanding/collapsing content via JavaScript.
Questions
- Is my understanding correct?
- Is there a recommended pattern for this kind of composition?
- Would it be possible (or desirable) to improve this? Might a solution be linked to the special
outerScopeandouterBlocksvariables?
Conceptually, this feels like a very common pattern (accordion, tabs, etc.), but
From my perspective, being able to build a Live “container” component that still allows the outer component to own the data and layout is a very common use case (accordions, tabs, modals, ...). With the current behavior, it feels surprisingly hard to achieve.
Thanks a lot for any clarification or guidance :)
Previous discussion
#844 seems to be related.