As we saw in the templates chapter, Emmett comes with a template engine out of the box, which you can use to render HTML.
Under specific circumstances though, it might be convenient generating HTML directly in your route code, using the Python language. To support these scenarios, Emmett provides few helpers under the html
module. Let's see them in details.
tag
helperThe tag
object is the main interface provided by Emmett to produce HTML contents from Python code. It dinamically produces HTML elements based on its attributes, so you can produce even custom elements:
from emmett.html import tag
# an empty <p></p>
p = tag.p()
# a custom element <card></card>
card = tag.card()
# a custom element <list-item></list-item>
list_item = tag["list-item"]()
Every element produced by the tag
helper accepts both nested contents and attributes, with the caveat HTML attributes needs to start with _
:
# <p>Hello world</p>
p = tag.p("Hello world")
# <div class="foo"><p>bar</p></div>
div = tag.div(tag.p("bar"), _class="foo")
Note: the reasons behind the underscore notation for HTML attributes are mainly:
- to avoid issues with Python reserved words (eg:class
)
- to keep the ability to set custom attributes on the HTML objects in Python code but prevent those attributes to be rendered
Mind that the tag
helper already takes care of self-closing elements and escaping contents, so you don't have to worry about those.
– That's cool dude, but what if I need to set several attributes with the same prefix?
– Like with HTMX? Sure, just use a dictionary
# <button hx-post="/clicked" hx-swap="outerHTML">Click me</button>
btn = tag.button(
"Click me",
_hx={
"post": url("clicked"),
"swap": "outerHTML"
}
)
cat
helperSometimes you may need to stack together HTML elements without a parent. For such cases, the cat
helper can be used:
from emmett.html import cat, tag
# <p>hello</p><p>world</p>
multi_p = cat(tag.p("hello"), tag.p("world"))
All the elements produced with the tag
helper supports with
statements, so you can easily manage even complicated stacks. For instance the following code:
root = tag.div(_class="root")
with root:
with tag.div(_class="lv1"):
with tag.div(_class="lvl2"):
tag.p("foo")
tag.p("bar")
str(root)
will produce the following HTML:
<div class="root">
<div class="lvl1">
<div class="lvl2">
<p>foo</p>
<p>bar</p>
</div>
</div>
</div>
Note: when compared to templates, HTML generation from Python will be noticeably slower. For cases in which you want to render long and almost static HTML contents, using templates is preferable.