Skip to content

Commit 444686c

Browse files
committed
Add documentation about passing blocks to embedded components and their context
1 parent f0c5fea commit 444686c

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

src/TwigComponent/doc/index.rst

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,136 @@ The ``with`` data is what's mounted on the component object.
832832

833833
Embedded components *cannot* currently be used with LiveComponents.
834834

835+
Passing blocks to embedded components
836+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
837+
838+
By combining nested components and embedded components very powerful structures can be created.
839+
There's one important thing to remember: **each embedded component, a.k.a. a component with
840+
blocks, inside a template, a.k.a. a nested component, starts its own template**.
841+
Any blocks that are available in your component template are *NOT* available *inside* the embedded component.
842+
843+
Imagine this simple Alert component, which allows its content to be set by a higher component,
844+
for example a SuccessAlert component.
845+
846+
.. code-block:: html+twig
847+
848+
{# templates/alert.html.twig #}
849+
<div class="alert alert-{{ type }}">
850+
{% block content %}{% endblock %}
851+
</div>
852+
853+
.. code-block:: twig
854+
855+
{# templates/successAlert.html.twig #}
856+
{% component Alert with { type: 'success' } %}
857+
I can override the content, but that's pretty dull.
858+
{% endcomponent %}
859+
860+
What if this SuccessAlert component wants to make the content of its nested Alert component configurable?
861+
Well, you can use the special `outerBlocks` variable for those cases. This makes it possible to refer
862+
to blocks that are passed in from another higher component.
863+
864+
.. code-block:: twig
865+
866+
{# templates/successAlert.html.twig #}
867+
{% component Alert with { type: 'success' } %}
868+
{{ blocks(outerBlocks.content) }}
869+
{% endcomponent %}
870+
871+
.. code-block:: twig
872+
873+
{# templates/some_page.html.twig #}
874+
{% component SuccessAlert %}
875+
Look mom, I'm a complex component!
876+
{% endcomponent %}
877+
878+
Note that to pass a block multiple components down, each component would need to pass it along.
879+
880+
.. code-block:: twig
881+
882+
{# templates/level1.html.twig #}
883+
{% component Level2 %}
884+
{% block foo %}
885+
I'm providing/overriding the foo block of Level2
886+
{% endblock %}
887+
{% endcomponent %}
888+
889+
.. code-block:: twig
890+
891+
{# templates/level2.html.twig #}
892+
{% component Target %}
893+
{% block foo %}
894+
{# overriding the foo block of Target #}
895+
{# but actually passing it along from the upper component #}
896+
{# it could add some extra stuff here of course #}
897+
{# and even append/prepend the content of Target's foo block by using {{ parent() }} #}
898+
899+
{{ blocks(outerBlocks.foo) }}
900+
{% endblock %}
901+
{% endcomponent %}
902+
903+
.. code-block:: html+twig
904+
905+
{# templates/target.html.twig #}
906+
<div>{% block foo %}default content for foo{% endblock %}</div>
907+
908+
Context of embedded components
909+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
910+
911+
Every embedded component can be viewed as another template inside a template, hence the name.
912+
Or in other words, in the other direction, it's as if the embedded component's blocks are copy-pasted
913+
into that component's template. This has a few interesting consequences.
914+
915+
First of all, although `this` is referring to the component of the template into which an (embedded)
916+
component is nested, *INSIDE* an embedded component it is referring to the *embedded* component,
917+
*NOT* the component into which it's being nested.
918+
919+
.. code-block:: twig
920+
921+
{# templates/successAlert.html.twig #}
922+
{{ this.someFunction }} {# this refers to SuccessAlert #}
923+
924+
{% component Alert with { type: 'success' } %}
925+
{{ this.someFunction }} {# this refers to Alert! #}
926+
{% endcomponent %}
927+
928+
On the other hand, all variables are also available to the embedded component.
929+
930+
.. code-block:: twig
931+
932+
{# templates/successAlert.html.twig #}
933+
{% set name = 'Fabien' %}
934+
{% component Alert with { type: 'success' } %}
935+
Hello {{ name }}
936+
{% endcomponent %}
937+
938+
Note that even ALL variables from upper components are available to lower components. However,
939+
because variables are merged in the context, variables with the same name are overridden by
940+
lower components. (That's also why `this` refers to the embedded, or "current" component)
941+
942+
Finally, the most interesting thing is that, because the embedded components are literally
943+
resolved when rendering the nested component's template, you can even access the variables
944+
from THAT template as well. Again, it's as if the embedded component's blocks are being
945+
copy-pasted into the nested component's template.
946+
947+
.. code-block:: twig
948+
949+
{# templates/successAlert.html.twig #}
950+
{% for message in messages %}
951+
{% block message %}
952+
A default {{ message }}
953+
{% endblock %}
954+
{% endfor %}
955+
956+
.. code-block:: twig
957+
958+
{# templates/some_page.html.twig #}
959+
{% component SuccessAlert %}
960+
{% block message %}
961+
I can override the message block and access the {{ message }} too!
962+
{% endblock %}
963+
{% endcomponent %}
964+
835965
Component HTML Syntax
836966
---------------------
837967

0 commit comments

Comments
 (0)