Skip to content

Rendering components

Our calendar component can accept and pre-process data, defines its own CSS and JS, and can be used in templates.

...But how do we actually render the components into HTML?

There's 3 ways to render a component:

As a reminder, this is what the calendar component looks like:

[project root]/components/calendar/calendar.py
from django_components import Component, register

@register("calendar")
class Calendar(Component):
    template_file = "calendar.html"
    js_file = "calendar.js"
    css_file = "calendar.css"

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

1. Render the template¤

If you have embedded the component in a Django template using the {% component %} tag:

[project root]/templates/my_template.html
{% load component_tags %}
<div>
  {% component "calendar" date="2024-12-13" / %}
</div>

You can simply render the template with the Django tooling:

With django.shortcuts.render()¤

from django.shortcuts import render

context = {"date": "2024-12-13"}
rendered_template = render(request, "my_template.html", context)

With Template.render()¤

Either loading the template with get_template():

from django.template.loader import get_template

template = get_template("my_template.html")
context = {"date": "2024-12-13"}
rendered_template = template.render(context)

Or creating a new Template instance:

from django.template import Template

template = Template("""
{% load component_tags %}
<div>
  {% component "calendar" date="2024-12-13" / %}
</div>
""")
rendered_template = template.render()

2. Render the component¤

You can also render the component directly with Component.render(), without wrapping the component in a template.

from components.calendar import Calendar

calendar = Calendar
rendered_component = calendar.render()

You can pass args, kwargs, slots, and more, to the component:

from components.calendar import Calendar

calendar = Calendar
rendered_component = calendar.render(
    args=["2024-12-13"],
    kwargs={
        "extra_class": "my-class"
    },
    slots={
        "date": "<b>2024-12-13</b>"
    },
)

Info

Among other, you can pass also the request object to the render method:

from components.calendar import Calendar

calendar = Calendar
rendered_component = calendar.render(request=request)

The request object is required for some of the component's features, like using Django's context processors.

3. Render the component to HttpResponse¤

A common pattern in Django is to render the component and then return the resulting HTML as a response to an HTTP request.

For this, you can use the Component.render_to_response() convenience method.

render_to_response() accepts the same args, kwargs, slots, and more, as Component.render(), but wraps the result in an HttpResponse.

from components.calendar import Calendar

def my_view(request):
    response = Calendar.render_to_response(
        args=["2024-12-13"],
        kwargs={
            "extra_class": "my-class"
        },
        slots={
            "date": "<b>2024-12-13</b>"
        },
        request=request,
    )
    return response

Info

Response class of render_to_response

While render method returns a plain string, render_to_response wraps the rendered content in a "Response" class. By default, this is django.http.HttpResponse.

If you want to use a different Response class in render_to_response, set the Component.response_class attribute:

class MyCustomResponse(HttpResponse):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        # Configure response
        self.headers = ...
        self.status = ...

class SimpleComponent(Component):
    response_class = MyCustomResponse

Rendering slots¤

Slots content are automatically escaped by default to prevent XSS attacks.

In other words, it's as if you would be using Django's mark_safe() function on the slot content:

from django.utils.safestring import mark_safe

class Calendar(Component):
    template = """
        <div>
            {% slot "date" default date=date / %}
        </div>
    """

Calendar.render(
    slots={
        "date": mark_safe("<b>Hello</b>"),
    }
)

To disable escaping, you can pass escape_slots_content=False to Component.render() or Component.render_to_response() methods.

Warning

If you disable escaping, you should make sure that any content you pass to the slots is safe, especially if it comes from user input!

Info

If you're planning on passing an HTML string, check Django's use of format_html and mark_safe.

Component views and URLs¤

For web applications, it's common to define endpoints that serve HTML content (AKA views).

If this is your case, you can define the view request handlers directly on your component by using the nestedComponent.View class.

This is a great place for:

  • Endpoints that render whole pages, if your component is a page component.

  • Endpoints that render the component as HTML fragments, to be used with HTMX or similar libraries.

Read more on Component views and URLs.

[project root]/components/calendar.py
from django_components import Component, ComponentView, register

@register("calendar")
class Calendar(Component):
    template = """
        <div class="calendar-component">
            <div class="header">
                {% slot "header" / %}
            </div>
            <div class="body">
                Today's date is <span>{{ date }}</span>
            </div>
        </div>
    """

    class View:
        # Handle GET requests
        def get(self, request, *args, **kwargs):
            # Return HttpResponse with the rendered content
            return Calendar.render_to_response(
                request=request,
                kwargs={
                    "date": request.GET.get("date", "2020-06-06"),
                },
                slots={
                    "header": "Calendar header",
                },
            )

Info

The View class supports all the same HTTP methods as Django's View class. These are:

get(), post(), put(), patch(), delete(), head(), options(), trace()

Each of these receive the HttpRequest object as the first argument.

Next, you need to set the URL for the component.

You can either:

  1. Automatically assign the URL by setting the Component.Url.public attribute to True.

    In this case, use get_component_url() to get the URL for the component view.

    from django_components import Component, get_component_url
    
    class Calendar(Component):
        class Url:
            public = True
    
    url = get_component_url(Calendar)
    
  2. Manually assign the URL by setting Component.as_view() to your urlpatterns:

    from django.urls import path
    from components.calendar import Calendar
    
    urlpatterns = [
        path("calendar/", Calendar.as_view()),
    ]
    

And with that, you're all set! When you visit the URL, the component will be rendered and the content will be returned.

The get(), post(), etc methods will receive the HttpRequest object as the first argument. So you can parametrize how the component is rendered for example by passing extra query parameters to the URL:

http://localhost:8000/calendar/?date=2024-12-13