Skip to content

Components in templates

By the end of this section, we want to be able to use our components in Django templates like so:

{% load component_tags %}
<!DOCTYPE html>
<html>
  <head>
    <title>My example calendar</title>
  </head>
  <body>
    {% component "calendar" / %}
  </body>
<html>

1. Register component¤

First, however, we need to register our component class with ComponentRegistry.

To register a component with a ComponentRegistry, we will use the @register decorator, and give it a name under which the component will be accessible from within the template:

[project root]/components/calendar/calendar.py
from django_components import Component, register  # <--- new

@register("calendar")  # <--- new
class Calendar(Component):
    template_name = "calendar.html"

    class Media:
        js = "calendar.js"
        css = "calendar.css"

    def get_context_data(self):
        return {
            "date": "1970-01-01",
        }

This will register the component to the default registry. Default registry is loaded into the template by calling {% load component_tags %} inside the template.

Info

Why do we have to register components?

We want to use our component as a template tag ({% ... %}) in Django template.

In Django, template tags are managed by the Library instances. Whenever you include {% load xxx %} in your template, you are loading a Library instance into your template.

ComponentRegistry acts like a router and connects the registered components with the associated Library.

That way, when you include {% load component_tags %} in your template, you are able to "call" components like {% component "calendar" / %}.

ComponentRegistries also make it possible to group and share components as standalone packages. Learn more here.

Note

You can create custom ComponentRegistry instances, which will use different Library instances. In that case you will have to load different libraries depending on which components you want to use:

Example 1 - Using component defined in the default registry

{% load component_tags %}
<div>
  {% component "calendar" / %}
</div>

Example 2 - Using component defined in a custom registry

{% load my_custom_tags %}
<div>
  {% my_component "table" / %}
</div>

Note that, because the tag name component is use by the default ComponentRegistry, the custom registry was configured to use the tag my_component instead. Read more here

2. Load and use the component in template¤

The component is now registered under the name calendar. All that remains to do is to load and render the component inside a template:

{% load component_tags %}  {# Load the default registry #}
<!DOCTYPE html>
<html>
  <head>
    <title>My example calendar</title>
  </head>
  <body>
    {% component "calendar" / %}  {# Render the component #}
  </body>
<html>

Info

Component tags should end with / if they do not contain any Slot fills. But you can also use {% endcomponent %} instead:

{% component "calendar" %}{% endcomponent %}

We defined the Calendar's template as

<div class="calendar">
  Today's date is <span>{{ date }}</span>
</div>

and the variable date as "1970-01-01".

Thus, the final output will look something like this:

<!DOCTYPE html>
<html>
  <head>
    <title>My example calendar</title>
    <style>
      .calendar {
        width: 200px;
        background: pink;
      }
      .calendar span {
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <div class="calendar">
      Today's date is <span>1970-01-01</span>
    </div>
    <script>
      (function () {
        document.querySelector(".calendar").onclick = () => {
          alert("Clicked calendar!");
        };
      })();
    </script>
  </body>
<html>

This makes it possible to organize your front-end around reusable components, instead of relying on template tags and keeping your CSS and Javascript in the static directory.

Info

Remember that you can use {% component_js_dependencies %} and {% component_css_dependencies %} to change where the <script> and <style> tags will be rendered (See JS and CSS output locations).

Info

How does django-components pick up registered components?

Notice that it was enough to add @register to the component. We didn't need to import the component file anywhere to execute it.

This is because django-components automatically imports all Python files found in the component directories during an event called Autodiscovery.

So with Autodiscovery, it's the same as if you manually imported the component files on the ready() hook:

class MyApp(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "myapp"

    def ready(self):
        import myapp.components.calendar
        import myapp.components.table
        ...

You can now render the components! But our component will render the same content now matter where and how many times we use it. Let's parametrise some of its state, so that our Calendar component is configurable from within the template ➡️