Templating
Flare's content elements render Twig templates. In current Flare versions, the flare variable in those templates is
an Engine object. To access list or reader data, create a view explicitly in Twig with flare.createView.
Use the bundled templates as your starting point. They reflect the current runtime API.
Current Templating Model
Older Flare documentation referred to Twig helpers such as flare_form(...), flare_make_list(...), and direct access
to flare.entries. That is no longer the current model.
Today:
flareis the engine injected by the content element controllerflare.createViewcreates the runtime view object for the current context- list templates work with an
InteractiveView - reader templates work with a
ValidationView
Template Locations
Bundled Templates
The bundled templates live in:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/
The main content element templates are:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/content_element/flare_listview.html.twig
vendor/heimrichhannot/contao-flare-bundle/contao/templates/content_element/flare_reader.html.twig
Related partials live in:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/flare/
Custom Templates
To override or extend the provided templates, create Twig files in a Twig template directory of your Contao
installation. Assuming there is a .twig-root file in contao/templates/, a typical structure looks like this:
contao/templates/content_element/{flare_listview,flare_reader}/my_variant.html.twig
You can then select the variant via the content element's customTpl field.
List View Templating
The default list template creates an interactive view first and then renders the filter form, entries, and paginator from that view.
{% extends "@Contao/content_element/flare_listview.html.twig" %}
{% set flare_list = flare.createView %}
{% block filter %}
{% set form = flare_list.form.createView %}
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">{{ 'submit'|trans({}, 'flare_form') }}</button>
{{ form_end(form) }}
{% endblock %}
{% block list %}
{% for entry in flare_list.entries %}
{% set href = flare_list.to(entry.id) %}
<article>
<h3>
{% if href %}
<a href="{{ href }}">{{ entry.headline ?? entry.title ?? '' }}</a>
{% else %}
{{ entry.headline ?? entry.title ?? '' }}
{% endif %}
</h3>
</article>
{% else %}
<p>No entries found.</p>
{% endfor %}
{% endblock %}
{% block pagination %}
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator
}) }}
{% endblock %}
Available Variables in List Templates
The list content element injects these template variables:
flare: theEnginecontent_model: thetl_contentmodel of the current content elementheadline: the normalized Contao headline data
After creating the view with flare.createView, you typically work with:
flare_list.form: the Symfony form objectflare_list.entries: the current result setflare_list.paginator: the paginatorflare_list.count: the total result countflare_list.to(id): the reader URL for an entry, if configuredflare_list.model(id): theContao\Modelinstance for a specific entry
Entries and Models
In list templates, flare_list.entries yields associative arrays for the current result set.
If you need access to the full model collection directly, use flare_list.models:
{% for model in flare_list.models %}
<h3>{{ model.headline ?? model.title ?? '' }}</h3>
{% endfor %}
If you need models only occasionally, you can still iterate over flare_list.entries and resolve a specific model from
the current entry:
{% for entry in flare_list.entries %}
{% set model = flare_list.model(entry.id) %}
<h3>{{ model.headline ?? entry.headline ?? '' }}</h3>
{% endfor %}
- Use
flare_list.entrieswhen the raw result data is sufficient. - If you only need models occasionally throughout the loop, using
flare_list.model(entry.id)is perfectly fine. - If you need models throughout the whole loop,
flare_list.modelsis the better choice than resolving each model individually.
Customizing the Filter Form
The filter form is a normal Symfony form. Create the form view from flare_list.form and apply form themes as usual.
{# {% set flare_list = flare.createView %} if not yet created #}
{% set form = flare_list.form.createView %}
You can access individual form fields by their field name. That field name is also used for the submitted query
parameter. For example, if a field is named search, you can access it as form.search:
{% set search_field = form.search %}
{{ form_row(search_field) }}
{% block filter %}
{% set flare_list = flare.createView %}
{% set form = flare_list.form.createView %}
{% form_theme form with [
'bootstrap_5_layout.html.twig',
'form/my_symfony_form_theme.html.twig',
] %}
{{ form_start(form) }}
{% set search_field = form.search %}
<div class="my-form-fields">
<div class="my-custom-search-field">
{{ form_row(search_field) }}
</div>
{{ form_rest(form) }}
</div>
{% block submit %}
<button type="submit">Apply filter</button>
{% endblock %}
{% block reset %}
<button type="reset" class="visually-hidden-focusable">Reset filter</button>
{% endblock %}
{{ form_end(form) }}
{% endblock %}
Because form themes are standard Symfony form themes, place them in templates/form/ relative to the project root, not
in the Contao templates directory.
Reader Templating
The reader content element renders a single model. Its default template extends the same base template as the list view, but works with reader-specific variables.
{% extends "@Contao/content_element/flare_reader.html.twig" %}
{% block content %}
<article>
<h1>{{ model.headline ?? model.title ?? '' }}</h1>
{% if model.teaser %}
<div>
{{ model.teaser|raw }}
</div>
{% endif %}
</article>
{% endblock %}
Available Variables in Reader Templates
The reader content element injects these variables:
flare: theEngineflare_reader: theValidationViewmodel: the resolvedContao\Modelfor the current reader itemcontent_model: thetl_contentmodel of the current content elementheadline: the normalized Contao headline datacomments: optional comments data when the comments integration attaches it
The reader template can also use flare_reader.to(id) if you need to generate reader links from the validation view.
Block Structure
These are the main blocks available for extension.
Base Template
@Contao/flare/_flare_base.html.twig defines:
wrapperheadlinecontentfooter
List Template
@Contao/content_element/flare_listview.html.twig adds:
content_startfilterlistpaginationcontent_end
Reader Template
@Contao/content_element/flare_reader.html.twig mainly customizes:
contentfooter
Paginator Templates
Flare ships several paginator templates.
Default paginator
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator
}) }}
The default paginator supports use_default_styles:
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator,
use_default_styles: true
}) }}
Bootstrap 5 variants
Flare also ships:
@Contao/flare/paginator/bs5.html.twig@Contao/flare/paginator/bs5_extended.html.twig
These are useful if you want Bootstrap-compatible paginator markup instead of the default Flare-specific markup.
Comments Integration
The default reader template renders comments in its footer block if comments data is present:
{% block footer %}
{% if comments|default(false) %}
{{ include('@Contao/flare/comments/basic.html.twig', comments) }}
{% endif %}
{% endblock %}
Comments are not universally available. They are attached by Flare's comments integration when the current list and reader setup supports them.
Twig Helpers
Flare currently registers these Twig functions:
flare_contentflare_enclosureflare_enclosure_filesflare_make_filterflare_projectflare_copy_viewflare_schema_org
These are lower-level helpers for advanced use cases. They are not a replacement for the standard content-element templating workflow described above.
Migration Notes
When updating older custom templates:
- replace
flare_form(...)withflare.createViewfollowed byflare_list.form.createView - replace direct
flare.entriesandflare.paginatoraccess with properties on the created view - remove any use of
flare_make_list(...), which is no longer part of the current Twig API - access all current list models via
flare_list.modelswhen you need the full collection