1# Templates
2
3**Render HTML templates using Jinja.**
4
5Plain uses Jinja2 for template rendering. You can refer to the [Jinja documentation](https://jinja.palletsprojects.com/en/stable/api/) for all of the features available.
6
7In general, templates are used in combination with `TemplateView` or a more specific subclass of it.
8
9```python
10from plain.views import TemplateView
11
12
13class ExampleView(TemplateView):
14 template_name = "example.html"
15
16 def get_template_context(self):
17 context = super().get_template_context()
18 context["message"] = "Hello, world!"
19 return context
20```
21
22```html
23<!-- example.html -->
24{% extends "base.html" %}
25
26{% block content %}
27 <h1>{{ message }}</h1>
28{% endblock %}
29```
30
31## Template files
32
33Template files can be located in either a root `app/templates`,
34or the `<pkg>/templates` directory of any installed package.
35
36All template directories are "merged" together, allowing you to override templates from other packages. The `app/templates` will take priority, followed by `INSTALLED_PACKAGES` in the order they are defined.
37
38## Extending Jinja
39
40Plain includes a set of default [global variables](jinja/globals.py) and [filters](jinja/filters.py). You can register additional extensions, globals, or filters either in a package or in your app. Typically this will be in `app/templates.py` or `<pkg>/templates.py`, which are automatically imported.
41
42```python
43# app/templates.py
44from plain.templates import register_template_filter, register_template_global, register_template_extension
45from plain.templates.jinja.extensions import InclusionTagExtension
46from plain.runtime import settings
47
48
49@register_template_filter
50def camel_case(value):
51 return value.replace("_", " ").title().replace(" ", "")
52
53
54@register_template_global
55def app_version():
56 return "1.0.0"
57
58
59@register_template_extension
60class HTMXJSExtension(InclusionTagExtension):
61 tags = {"htmx_js"}
62 template_name = "htmx/js.html"
63
64 def get_context(self, context, *args, **kwargs):
65 return {
66 "csrf_token": context["csrf_token"],
67 "DEBUG": settings.DEBUG,
68 "extensions": kwargs.get("extensions", []),
69 }
70```
71
72## Rendering templates manually
73
74Templates can also be rendered manually using the [`Template` class](core.py#Template).
75
76```python
77from plain.templates import Template
78
79comment_body = Template("comment.md").render({"message": "Hello, world!",})
80```