Working with objects that know how to render themselves as elements on an HTML template is a common pattern seen throughout the Wagtail admin. For example, the admin homepage is a view provided by the central `wagtail.admin` app, but brings together information panels sourced from various other modules of Wagtail, such as images and documents (potentially along with others provided by third-party packages). These panels are passed to the homepage via the [`construct_homepage_panels`](construct_homepage_panels) hook, and each one is responsible for providing its own HTML rendering. In this way, the module providing the panel has full control over how it appears on the homepage.
Wagtail implements this pattern using a standard object type known as a **component**. A component is a Python object that provides the following methods and properties:
Given a context dictionary from the calling template (which may be a :py:class:`Context <django.template.Context>` object or a plain ``dict`` of context variables), returns the string representation to be inserted into the template. This will be subject to Django's HTML escaping rules, so a return value consisting of HTML should typically be returned as a :py:mod:`SafeString <django.utils.safestring>` instance.
.. attribute:: media
A (possibly empty) :doc:`form media <django:topics/forms/media>` object defining JavaScript and CSS resources used by the component.
Any object implementing this API can be considered a valid component; it does not necessarily have to inherit from the `Component` class described below, and user code that works with components should not assume this (for example, it must not use `isinstance` to check whether a given value is a component).
Starting with version 6.0, Wagtail uses the [Laces](https://pypi.org/project/laces/) library to provide all the component related implementations.
The Laces library was extracted from Wagtail to make the concept of "template components" available to the wider Django ecosystem.
All import paths shown below continue to work, but they are only references to the implementations in Laces.
"Template components" are not restricted to extensions of the Wagtail admin. You can use the concepts and tools below in your user-facing code as well.
You can find more information on the use of components in the [Laces documentation](https://github.com/tbrlpld/laces/blob/main/README.md).
The preferred way to create a component is to define a subclass of `wagtail.admin.ui.components.Component` and specify a `template_name` attribute on it. The rendered template will then be used as the component's HTML representation:
For simple cases that don't require a template, the `render_html` method can be overridden instead:
```python
from django.utils.html import format_html
from wagtail.admin.components import Component
class WelcomePanel(Component):
def render_html(self, parent_context):
return format_html("<h1>{}</h1>", "Welcome to my app!")
```
## Passing context to the template
The `get_context_data` method can be overridden to pass context variables to the template. As with `render_html`, this receives the context dictionary from the calling template:
Like Django form widgets, components can specify associated JavaScript and CSS resources using either an inner `Media` class or a dynamic `media` property:
```python
class WelcomePanel(Component):
template_name = 'my_app/panels/welcome.html'
class Media:
css = {
'all': ('my_app/css/welcome-panel.css',)
}
```
## Using components on your own templates
The `wagtailadmin_tags` tag library provides a `{% component %}` tag for including components on a template. This takes care of passing context variables from the calling template to the component (which would not be the case for a basic `{{ ... }}` variable tag). For example, given the view:
```python
from django.shortcuts import render
def welcome_page(request):
panels = [
WelcomePanel(),
]
render(request, 'my_app/welcome.html', {
'panels': panels,
})
```
the `my_app/welcome.html` template could render the panels as follows:
Note that it is your template's responsibility to output any media declarations defined on the components. For a Wagtail admin view, this is best done by constructing a media object for the whole page within the view, passing this to the template, and outputting it via the base template's `extra_js` and `extra_css` blocks: