HTML¶
The html-tstring package renders PEP 750 t-string templates to safe HTML.
Basic rendering¶
from html_tstring import render_html
name = "world"
page = render_html(t"<h1>Hello, {name}!</h1>")
# <h1>Hello, world!</h1>
Interpolated text is HTML-escaped automatically:
user_input = '<img src=x onerror="alert(1)">'
safe = render_html(t"<p>{user_input}</p>")
# <p><img src=x onerror="alert(1)"></p>
Raw HTML¶
Use RawHtml when you have trusted HTML that should not be escaped:
from html_tstring import RawHtml, render_html
icon = RawHtml('<svg><circle r="5"/></svg>')
render_html(t"<span>{icon}</span>")
# <span><svg><circle r="5"/></svg></span>
RawHtml works in child and fragment positions. In attributes and spread values it is treated as a plain string and escaped normally. Interpolation inside raw-text elements (<script>, <style>, etc.) is rejected.
Attributes¶
Dynamic attribute values¶
Quoted dynamic attribute values are always supported:
from html_tstring import render_html
href = "/dashboard"
render_html(t'<a href="{href}">Dashboard</a>')
# <a href="/dashboard">Dashboard</a>
A dynamic attribute interpolation must be quoted in v1. Unquoted dynamic attributes are rejected during validation:
title = "safe & sound"
render_html(t'<div title="{title}"></div>')
# <div title="safe & sound"></div>
Boolean attributes¶
True renders a bare attribute. False and None omit it:
from html_tstring import render_html
disabled = True
hidden = False
render_html(t"<button disabled={disabled} hidden={hidden}>OK</button>")
# <button disabled>OK</button>
Class normalization¶
The class attribute accepts strings, lists, and dict-like mappings:
from html_tstring import render_html
classes = ["btn", {"btn-primary": True, "btn-disabled": False}]
render_html(t'<button class="{classes}">Click</button>')
# <button class="btn btn-primary">Click</button>
Spread attributes¶
A bare interpolation inside a start tag is treated as a spread:
from html_tstring import render_html
attrs = {"data-id": "42", "class": "extra", "hidden": False}
render_html(t'<div class="base" {attrs}>content</div>')
# <div class="base extra" data-id="42">content</div>
Spread merge rules:
- Attributes are applied left to right in source order
- For non-
classattributes, later values replace earlier ones - For
class, values are concatenated in source order Truerenders a bare attribute,False/Noneomits it
Fragment rendering¶
render_fragment works the same as render_html:
from html_tstring import render_fragment
name = "world"
render_fragment(t"<p>{name}</p>")
# <p>world</p>
Fragment children¶
Use Fragment to pass multiple children:
from html_tstring import Fragment, RawHtml, render_html
children = Fragment([RawHtml("<em>first</em>"), "second"])
render_html(t"<div>{children}</div>")
# <div><em>first</em>second</div>
Template validation¶
check_template validates syntax without rendering:
from html_tstring import check_template
check_template(t"<div>valid</div>") # OK
check_template(t"<Button />") # TemplateSemanticError: component tags need thtml-tstring
Template formatting¶
format_template gives back the template source with canonical formatting:
from html_tstring import format_template
name = "world"
format_template(t"<div>{name}</div>")
# '<div>{name}</div>'
Raw-text elements¶
Interpolation inside <script>, <style>, <title>, and <textarea> is rejected: