django-components/docs/concepts/advanced/component_context_scope.md
Juro Oravec ccf02fa316
chore: util to manage URLs in the codebase (#1179)
* chore: util to manage URLs in the codebase

* docs: mentiion validate_links and supported_versions in docs

* refactor: fix linter errors
2025-05-11 14:59:34 +02:00

6.4 KiB
Raw Blame History

By default, context variables are passed down the template as in regular Django - deeper scopes can access the variables from the outer scopes. So if you have several nested forloops, then inside the deep-most loop you can access variables defined by all previous loops.

With this in mind, the {% component %} tag behaves similarly to {% include %} tag - inside the component tag, you can access all variables that were defined outside of it.

And just like with {% include %}, if you don't want a specific component template to have access to the parent context, add only to the {% component %} tag:

{% component "calendar" date="2015-06-19" only / %}

NOTE: {% csrf_token %} tags need access to the top-level context, and they will not function properly if they are rendered in a component that is called with the only modifier.

If you find yourself using the only modifier often, you can set the context_behavior option to "isolated", which automatically applies the only modifier. This is useful if you want to make sure that components don't accidentally access the outer context.

Components can also access the outer context in their context methods like get_template_data by accessing the property self.outer_context.

Example of Accessing Outer Context

<div>
  {% component "calender" / %}
</div>

Assuming that the rendering context has variables such as date, you can use self.outer_context to access them from within get_template_data. Here's how you might implement it:

class Calender(Component):

    ...

    def get_template_data(self, args, kwargs, slots, context):
        outer_field = self.outer_context["date"]
        return {
            "date": outer_fields,
        }

However, as a best practice, its recommended not to rely on accessing the outer context directly through self.outer_context. Instead, explicitly pass the variables to the component. For instance, continue passing the variables in the component tag as shown in the previous examples.

Context behavior

django_components supports both Django and Vue-like behavior when it comes to passing data to and through components. This can be configured in context_behavior.

This has two modes:

  • "django"

    The default Django template behavior.

    Inside the {% fill %} tag, the context variables you can access are a union of:

  • "isolated"

    Similar behavior to Vue or React, this is useful if you want to make sure that components don't accidentally access variables defined outside of the component.

    Inside the {% fill %} tag, you can ONLY access variables from 2 places:

!!! warning

Notice that the component whose `get_template_data()` we use inside
[`{% fill %}`](../../../reference/template_tags#fill)
is NOT the same across the two modes!

Consider this example:

```djc_py
class Outer(Component):
    template = """
      <div>
        {% component "inner" %}
          {% fill "content" %}
            {{ my_var }}
          {% endfill %}
        {% endcomponent %}
      </div>
    """
```

- `"django"` - `my_var` has access to data from `get_template_data()` of both `Inner` and `Outer`.
  If there are variables defined in both, then `Inner` overshadows `Outer`.

- `"isolated"` - `my_var` has access to data from `get_template_data()` of ONLY `Outer`.

Example "django"

Given this template:

@register("root_comp")
class RootComp(Component):
    template = """
        {% with cheese="feta" %}
            {% component 'my_comp' %}
                {{ my_var }}  # my_var
                {{ cheese }}  # cheese
            {% endcomponent %}
        {% endwith %}
    """

    def get_template_data(self, args, kwargs, slots, context):
        return { "my_var": 123 }

Then if get_template_data() of the component "my_comp" returns following data:

{ "my_var": 456 }

Then the template will be rendered as:

456   # my_var
feta  # cheese

Because "my_comp" overshadows the outer variable "my_var", so {{ my_var }} equals 456.

And variable "cheese" equals feta, because the fill CAN access all the data defined in the outer layers, like the {% with %} tag.

Example "isolated"

Given this template:

class RootComp(Component):
    template = """
        {% with cheese="feta" %}
            {% component 'my_comp' %}
                {{ my_var }}  # my_var
                {{ cheese }}  # cheese
            {% endcomponent %}
        {% endwith %}
    """

    def get_template_data(self, args, kwargs, slots, context):
        return { "my_var": 123 }

Then if get_template_data() of the component "my_comp" returns following data:

{ "my_var": 456 }

Then the template will be rendered as:

123   # my_var
    # cheese

Because variables "my_var" and "cheese" are searched only inside RootComponent.get_template_data(). But since "cheese" is not defined there, it's empty.

!!! info

Notice that the variables defined with the [`{% with %}`](https://docs.djangoproject.com/en/5.2/ref/templates/builtins/#with)
tag are ignored inside the [`{% fill %}`](../../../reference/template_tags#fill) tag with the `"isolated"` mode.