Summary
When overriding a block inside {% embed ... only %}, the block body executes in the embedded template's scope, not the calling template's. So variables available at the call site aren't available inside the block unless explicitly passed via with. This is surprising for component development, and as far as I can tell it isn't documented.
Minimal reproduction
{# component.twig #}
{% block content %}{% endblock %}
{# page.twig #}
{% set msg = 'hello' %}
{% embed 'child.twig' with {} only %}
{% block content %}{{ msg }}{% endblock %} {# msg is undefined #}
{% endembed %}
Remove only and it renders hello, which confirms the behavior is specifically the context-trimming of only — the override block resolves msg against the embedded scope, which only has emptied.
Why it's surprising
The block is written at the call site, but it runs in the embedded template's context. That write/run split is not terribly obvious, and it's the piece the embed docs don't currently explain.
Based on the related issues linked below, I understand this is intentional, but I'm flagging that it's undocumented and ergonomically rough for a growing use case.
Motivation: Drupal's Single Directory Components
Drupal's Single Directory Components build on embed, giving components "props" (the with mapping) and "slots" (blocks) — a model very similar to React or web components. The SDC docs explicitly recommend only "to avoid unexpected side-effects," and Drupal theme contexts are large, so only is the norm. The result is that slot content can't see call-site variables unless they're also threaded through props, which is unexpected coming from other component systems.
Ask
- Docs: Could the embed page state explicitly that override blocks execute in the embedded template's scope, and that
only therefore excludes call-site variables from those blocks?
- Design (open question): Is there any way to alleviate this perceived quirk?
Related
Summary
When overriding a block inside {% embed ... only %}, the block body executes in the embedded template's scope, not the calling template's. So variables available at the call site aren't available inside the block unless explicitly passed via
with. This is surprising for component development, and as far as I can tell it isn't documented.Minimal reproduction
Remove
onlyand it rendershello, which confirms the behavior is specifically the context-trimming ofonly— the override block resolvesmsgagainst the embedded scope, which only has emptied.Why it's surprising
The block is written at the call site, but it runs in the embedded template's context. That write/run split is not terribly obvious, and it's the piece the embed docs don't currently explain.
Based on the related issues linked below, I understand this is intentional, but I'm flagging that it's undocumented and ergonomically rough for a growing use case.
Motivation: Drupal's Single Directory Components
Drupal's Single Directory Components build on
embed, giving components "props" (thewithmapping) and "slots" (blocks) — a model very similar to React or web components. The SDC docs explicitly recommendonly"to avoid unexpected side-effects," and Drupal theme contexts are large, soonlyis the norm. The result is that slot content can't see call-site variables unless they're also threaded through props, which is unexpected coming from other component systems.Ask
onlytherefore excludes call-site variables from those blocks?Related