Jinja Templating
Basics
To start serving HTML and HTMX requests, all you need to do is create an instance of fasthx.Jinja
and use its hx()
or page()
methods as decorators on your routes. hx()
only triggers HTML rendering for HTMX requests, while page()
unconditionally renders HTML, saving you some boilerplate code. See the example code below:
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from fasthx import Jinja
from pydantic import BaseModel
# Pydantic model of the data the example API is using.
class User(BaseModel):
first_name: str
last_name: str
# Create the app.
app = FastAPI()
# Create a FastAPI Jinja2Templates instance and use it to create a
# FastHX Jinja instance that will serve as your decorator.
jinja = Jinja(Jinja2Templates("templates"))
@app.get("/")
@jinja.page("index.html")
def index() -> None:
...
@app.get("/user-list")
@jinja.hx("user-list.html")
async def htmx_or_data() -> list[User]:
return [
User(first_name="John", last_name="Lennon"),
User(first_name="Paul", last_name="McCartney"),
User(first_name="George", last_name="Harrison"),
User(first_name="Ringo", last_name="Starr"),
]
@app.get("/admin-list")
@jinja.hx("user-list.html", no_data=True)
def htmx_only() -> list[User]:
return [User(first_name="Billy", last_name="Shears")]
Using TemplateHeader
In the basic example, routes always rendered a fixed HTML template. TemplateHeader
lifts this restriction by letting the client submit the key of the required template,
automatically looking up the corresponding template, and of course rendering it.
This can be particularly helpful when multiple templates/UI components require the same data and business logic.
app = FastAPI()
jinja = Jinja(Jinja2Templates("templates"))
@app.get("/profile/{id}")
@jinja.hx(
TemplateHeader(
"X-Component",
{
"card": "profile/card.jinja",
"form": "profile/form.jinja",
},
default="profile/card.jinja",
),
)
def get_user_by_id(id: int) -> User:
return get_user_from_db(id)
Given the example above, if the client submits an HX-Request
which includes an X-Component
header, the server will render profile/card.jinja
if X-Component
's value is "card"
, and profile/form.jinja
if the value is "form"
. If the X-Component
header is missing, the default (profile/card.jinja
) will be rendered.
If you're tired of repeating "profile/"
, you can just set prefix="profile"
in the hx()
(or page()
) decorator.