Usage¶
Elements are imported directly from the htpy
module as their name. HTML attributes are specified by parenthesis (()
/ "call"). Children are specified using square brackets ([]
/ "getitem").
Elements¶
Children can be strings, markup, other elements or lists/iterators.
Elements can be arbitrarily nested:
>>> from htpy import article, section, p
>>> print(section[article[p["Lorem ipsum"]]])
<section><article><p>Lorem ipsum</p></article></section>
Text/strings¶
It is possible to pass a string directly:
>>> from htpy import h1
>>> print(h1["Welcome to my site!"])
<h1>Welcome to my site!</h1>
Strings are automatically escaped to avoid XSS vulnerabilities. It is convenient and safe to directly insert variable data via f-strings:
>>> from htpy import h1
>>> user_supplied_name = "bobby </h1>"
>>> print(h1[f"hello {user_supplied_name}"])
<h1>hello bobby </h1></h1>
Conditional rendering¶
None
will not render anything. This can be useful to conditionally render some content.
>>> from htpy import div, b
>>> error = None
>>> # No <b> tag will be rendered since error is None
>>> print(div[error and b[error]])
<div></div>
>>> error = 'Enter a valid email address.'
>>> print(div[error and b[error]])
<div><b>Enter a valid email address.</b></div>
# Inline if/else can also be used:
>>> print(div[b[error] if error else None])
<div><b>Enter a valid email address.</b></div>
Loops / iterating over children¶
You can pass a list, tuple or generator to generate multiple children:
>>> from htpy import ul, li
>>> print(ul[(li[letter] for letter in "abc")])
<ul><li>a</li><li>b</li><li>c</li></ul>
Note
The generator will be lazily evaluated when rendering the element, not directly when the element is constructed. See Streaming for more information.
A list
can be used similar to a JSX fragment:
>>> from htpy import div, img
>>> my_images = [img(src="a.jpg"), img(src="b.jpg")]
>>> print(div[my_images])
<div><img src="a.jpg"><img src="b.jpg"></div>
Custom elements / web components¶
Custom elements / web
components
are HTML elements that contains at least one dash (-
). Since -
cannot be
used in Python identifiers, use underscore (_
) instead:
>>> from htpy import my_custom_element
>>> print(my_custom_element['hi!'])
<my-custom-element>hi!</my-custom-element>
Injecting markup¶
If you have HTML markup that you want to insert without further escaping, wrap
it in Markup
from the markupsafe
library. markupsafe is a dependency of htpy and is automatically installed:
>>> from htpy import div
>>> from markupsafe import Markup
>>> print(div[Markup("<foo></foo>")])
<div><foo></foo></div>
If you are generate Markdown and want to insert it into an element, use Markup
:
>>> from markdown import markdown
>>> from markupsafe import Markup
>>> from htpy import div
>>> print(div[Markup(markdown('# Hi'))])
<div><h1>Hi</h1></div>
HTML Doctype¶
The HTML doctype is automatically prepended to the <html>
tag:
Attributes¶
HTML attributes are defined by calling the element. They can be specified in a couple of different ways.
Elements without attributes¶
Some elements do not have attributes, they can be specified by just the element itself:
Keyword arguments¶
Attributes can be specified via keyword arguments:
In Python, class
and for
cannot be used as keyword arguments. Instead, they can be specified as class_
or for_
when using keyword arguments:
Attributes that contains dashes -
can be specified using underscores:
id/class shorthand¶
Defining id
and class
attributes is common when writing HTML. A string shorthand
that looks like a CSS selector can be used to quickly define id and classes:
>>> from htpy import div
>>> print(div("#myid.foo.bar"))
<div id="myid" class="foo bar"></div>
Attributes as dict¶
Attributes can also be specified as a dict
. This is useful when using
attributes that are reserved Python keywords (like for
or class
), when the
attribute name contains a dash (-
) or when you want to define attributes
dynamically.
>>> from htpy import div
>>> print(div({"data-foo": "bar"}))
<div data-foo="bar"></div>
>>> from htpy import label
>>> print(label({"for": "myfield"}))
<label for="myfield"></label>
Boolean attributes¶
In HTML, boolean attributes such as disabled
are considered "true" when they
exist. Specifying an attribute as True
will make it appear (without a value).
False
will make it hidden. This is useful and brings the semantics of bool
to
HTML.
>>> from htpy import button
>>> print(button(disabled=True))
<button disabled></button>
Conditionally mixing CSS classes¶
To make it easier to mix CSS classes, the class
attribute
accepts a list of class names or a dict. Falsey values will be ignored.
>>> from htpy import button
>>> is_primary = True
>>> print(button(class_=["btn", {"btn-primary": is_primary}]))
<button class="btn btn-primary"></button>
>>> is_primary = False
>>> print(button(class_=["btn", {"btn-primary": is_primary}]))
<button class="btn"></button>
>>>
Combining modes¶
Attributes via id/class shorthand, keyword arguments and dictionary can be combined:
>>> from htyp import label
>>> print(label("#myid.foo.bar", {'for': "somefield"}, name="myname",))
<label id="myid" class="foo bar" for="somefield" name="myname"></label>
Iterating of the output¶
Iterating over a htpy element will yield the resulting contents in chunks as they are rendered: