Skip to content

Using slot and block tags¤

  1. First let's clarify how include and extends tags work inside components. So when component template includes include or extends tags, it's as if the "included" template was inlined. So if the "included" template contains slot tags, then the component uses those slots.

    So if you have a template `abc.html`:
    ```django
    <div>
      hello
      {% slot "body" %}{% endslot %}
    </div>
    ```
    
    And components that make use of `abc.html` via `include` or `extends`:
    ```py
    from django_components import Component, register
    
    @register("my_comp_extends")
    class MyCompWithExtends(Component):
        template = """{% extends "abc.html" %}"""
    
    @register("my_comp_include")
    class MyCompWithInclude(Component):
        template = """{% include "abc.html" %}"""
    ```
    
    Then you can set slot fill for the slot imported via `include/extends`:
    
    ```django
    {% component "my_comp_extends" %}
        {% fill "body" %}
            123
        {% endfill %}
    {% endcomponent %}
    ```
    
    And it will render:
    ```html
    <div>
      hello
      123
    </div>
    ```
    
  2. Slot and block

    So if you have a template abc.html like so:

    <div>
      hello
      {% block inner %}
        1
        {% slot "body" %}
          2
        {% endslot %}
      {% endblock %}
    </div>
    

    and component my_comp:

    @register("my_comp")
    class MyComp(Component):
        template_name = "abc.html"
    

    Then:

    1. Since the block wasn't overriden, you can use the body slot:

      {% component "my_comp" %}
          {% fill "body" %}
              XYZ
          {% endfill %}
      {% endcomponent %}
      

      And we get:

      <div>hello 1 XYZ</div>
      
    2. blocks CANNOT be overriden through the component tag, so something like this:

      {% component "my_comp" %}
          {% fill "body" %}
              XYZ
          {% endfill %}
      {% endcomponent %}
      {% block "inner" %}
          456
      {% endblock %}
      

      Will still render the component content just the same:

      <div>hello 1 XYZ</div>
      
    3. You CAN override the block tags of abc.html if my component template uses extends. In that case, just as you would expect, the block inner inside abc.html will render OVERRIDEN:

      @register("my_comp")
      class MyComp(Component):
      template_name = """
      {% extends "abc.html" %}
      
                  {% block inner %}
                      OVERRIDEN
                  {% endblock %}
              """
          ```
      
    4. This is where it gets interesting (but still intuitive). You can insert even new slots inside these "overriding" blocks:

      @register("my_comp")
      class MyComp(Component):
          template_name = """
              {% extends "abc.html" %}
      
              {% load component_tags %}
              {% block "inner" %}
                  OVERRIDEN
                  {% slot "new_slot" %}
                      hello
                  {% endslot %}
              {% endblock %}
          """
      

      And you can then pass fill for this new_slot when rendering the component:

      {% component "my_comp" %}
          {% fill "new_slot" %}
              XYZ
          {% endfill %}
      {% endcomponent %}
      

      NOTE: Currently you can supply fills for both new_slot and body slots, and you will not get an error for an invalid/unknown slot name. But since body slot is not rendered, it just won't do anything. So this renders the same as above:

      {% component "my_comp" %}
          {% fill "new_slot" %}
              XYZ
          {% endfill %}
          {% fill "body" %}
              www
          {% endfill %}
      {% endcomponent %}