Fabien Potencier
Contributed by Fabien Potencier in #4871

Twig templates can declare the types they expect, but until now they had no standard way to describe what their variables, blocks and macros represent.

The Problem

Projects that document template APIs often rely on custom conventions inside regular Twig comments. A component library, for example, might use annotations such as @prop and @block:

1
2
3
4
5
6
7
8
9
10
{# @prop id string Unique identifier for the accordion #}
{# @prop multiple boolean Whether several items can be open #}
{# @block content The accordion items #}

{% types {
    id: 'string',
    multiple?: 'boolean',
} %}

{% block content %}{% endblock %}

These annotations duplicate variable names and types already present in the types declaration. They also require every IDE, static analyzer and documentation generator to understand a project-specific format.

Documentation Comments

Twig 3.29 introduces documentation comments, a standard syntax for attaching human-readable descriptions to template constructs and variable declarations. They use the regular Twig comment delimiters with an additional #:

1
2
3
4
{## The accordion items displayed by this component. ##}
{% block content %}
    ...
{% endblock %}

Documentation comments can describe output expressions, built-in and custom tags, blocks and macros. The comment is associated with the construct that immediately follows it:

1
2
3
4
5
6
7
{## Displays the title of the current page. ##}
{{ page_title }}

{## Renders an HTML input. ##}
{% macro input(name, value = null) %}
    ...
{% endmacro %}

Consecutive documentation comments are combined, which lets you add more context without writing a long line:

1
2
3
{## Displays the main page content. ##}
{## The layout renders this block between the header and footer. ##}
{% block content %}{% endblock %}

Documenting Variable Bindings

Inside a Twig tag, documentation comments start with ## and continue until the end of the line. This keeps descriptions next to the declarations they explain without repeating names or types:

1
2
3
4
5
6
7
8
9
10
{% types {
    ## Unique identifier for the accordion.
    id: 'string',

    ## Whether several items can be open at the same time.
    multiple?: 'boolean',

    ## Value of the item that should initially be open.
    default_value?: 'string|null',
} %}

The existing types syntax remains unchanged. Required variables still use a plain name and optional variables still use the ? suffix. Documentation is additional metadata associated with each declaration.

The same syntax can describe assignment targets, loop variables and macro arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{% set
    ## The number of unread messages.
    unread_count = messages|filter(message => not message.read)|length
%}

{% for
    ## The product identifier.
    product_id,
    ## The product for the current iteration.
    product
    in products
%}
    ...
{% endfor %}

{% macro input(
    ## The HTML field name.
    name,
    ## The initial field value.
    value = null,
) %}
    ...
{% endmacro %}

Because an inline documentation comment consumes the rest of its line, the variable it describes must begin on a later line. Comments in unsupported positions remain regular comments and expose no metadata.

Metadata for Developer Tools

Documentation comments do not change compiled output or rendering. Twig attaches their contents to the parsed nodes, where node visitors can read them with Node::getDocumentation().

This gives tools a common source of metadata. An IDE can display descriptions during autocompletion, a static analyzer can include them in diagnostics and a component documentation generator can build an API reference directly from the template. The Twig declarations remain the source of truth for names, types and optionality.

Note

Symfony Language Tools understands Twig documentation comments. For variables declared with the types tag, completion and hover include the declared type, required or optional status and attached documentation.

Backward Compatibility and Experimental Status

The syntax was designed to degrade gracefully. Older Twig versions parse {## ... #} as a regular comment. Twig 3.15 and later also parse ## inside a tag as an ordinary inline comment, so templates using these versions can add documentation comments without changing their rendered output.

Documentation comments are experimental in Twig 3.29. Their syntax and metadata API can evolve based on feedback from template authors and tooling developers.

Published in #Living on the edge #Twig