The turbo_frame Twig filter
A Turbo Frame request only needs the content of the frame, not the page layout around it. The turbo_frame filter
picks the template to extend: the full one on a normal request, a lean one when the request targets a (matching) Turbo
Frame, without branching in every action:
{# convention: use project/show-frame.html.twig if it exists, #}{# otherwise fall back to the configured base_template #}{% extends 'project/show.html.twig'|turbo_frame('project-details') %}
{# or pass an explicit base template (skips the -frame lookup) #}{% extends 'project/show.html.twig'|turbo_frame('project-details', 'layout/_frame.html.twig') %}The filter is registered by the bundle when twig/twig is installed, or by hand
without the framework.
Arguments
Section titled “Arguments”{{ template|turbo_frame(frameId = null, baseTemplate = null) }}| Argument | Default | Effect |
|---|---|---|
template |
The template to extend outside the frame. | |
frameId |
null |
Only switch templates when the Turbo-Frame header equals this id; null matches any frame. |
baseTemplate |
null |
The template to extend inside the frame; skips the -frame lookup. |
Omit the frame id ('project/show.html.twig'|turbo_frame) to match any Turbo Frame request.
Resolution
Section titled “Resolution”| Request | Returned template |
|---|---|
No Turbo-Frame header, or another frame id than frameId |
template |
| No current request (console command, email, message handler) | template |
Matching frame, baseTemplate given |
baseTemplate |
Matching frame, the -frame sibling of template exists |
the sibling |
| Matching frame, otherwise | the configured base_template |
The -frame sibling convention
Section titled “The -frame sibling convention”When the frame matches and you don’t pass a base template, the filter first looks for a -frame sibling of the
template (project/show.html.twig → project/show-frame.html.twig). If that template exists it wins; otherwise the
filter falls back to the configured base_template. Passing an explicit base template skips the sibling lookup
entirely.
-frame is inserted before the first dot of the file name, never in a directory name:
| Template | Sibling looked for |
|---|---|
project/show.html.twig |
project/show-frame.html.twig |
v1.2/page.html.twig |
v1.2/page-frame.html.twig |
@App/admin.users/list.html.twig |
@App/admin.users/list-frame.html.twig |
partials/page |
partials/page-frame |
The lookup asks the Twig loader whether the sibling exists; it does not render it.
A frame layout
Section titled “A frame layout”Turbo extracts the <turbo-frame> whose id matches the requesting frame from the response, so the frame layout
needs that element, and the blocks of the full layout your pages fill. For example:
{# templates/base-frame.html.twig #}<turbo-frame id="{{ app.request.headers.get('Turbo-Frame') }}"> {% block body %}{% endblock %}</turbo-frame>{# templates/project/show.html.twig #}{% extends 'base.html.twig'|turbo_frame('project-details') %}
{% block body %} <h1>{{ project.name }}</h1>{% endblock %}A normal request renders the page in base.html.twig; a request from the project-details frame renders it in
base-frame.html.twig, the -frame sibling of base.html.twig.
