Mohtml allows you to quickly declare HTML from Python functions. This can be fun when building a webapp but it also has it's utility when working in a (marimo) notebook.
Install
uv pip install mohtml
Demo
After installing it you can get a good impression of what you can do by running this snippet:
from mohtml import a, p, div, script, h1
print(
div(
script(src="https://cdn.tailwindcss.com"),
h1("welcome to my blog", klass="font-bold text-xl"),
p("my name is vincent", klass="text-gray-500 text-sm"),
a("please check my site", href="https://calmcode.io", klass="underline")
)
)
When printed, or when cast as a string, the resulting html will look like this:
<div>
<script src="https://cdn.tailwindcss.com">
</script>
<h1 class="font-bold text-xl">
welcome to my blog
</h1>
<p class="text-gray-500 text-sm">
my name is vincent
</p>
<a class="underline" href="https://calmcode.io">
please check my site
</a>
</div>
The library is also very flexible and allows you to add any HTML attribute to your elements. Note how arguments of functions become children and notice how kwargs are turned into properties on the element. Keep in mind that the klass
keyword is used instead of class
because class
is a reserved keyword in Python.
You can also actually render the HTML, feel free to play around below.
import marimo as mo
from mohtml import a, p, div, script, h1
div(
script(src="https://cdn.tailwindcss.com"),
h1("welcome to my blog", klass="font-bold text-xl"),
p("my name is vincent", klass="text-gray-500 text-sm"),
a("please check my site", href="https://calmcode.io", klass="underline")
)
Representation
You can go a step further and represent Python objects with rich HTML too!
from mohtml import img, span
class CoolCat:
def __init__(self, name, nickname, desc, avatar):
self.name = name
self.nickname = nickname
self.desc = desc
self.avatar = avatar
def _display_(self):
return div(
div(
span(self.name, klass="text-xl font-bold text-black"),
span(" - "),
span(self.nickname, klass="text-gray-700"),
),
img(src=self.avatar, klass="rounded-lg"),
p(self.desc, klass="text-sm text-gray-900 pt-4"),
klass="bg-gray-200 rounded-lg p-4"
)
def __str__(self):
return str(self._display_())
CoolCat(
name="tank",
nickname="the hunter",
desc="takes a blue pill daily",
avatar="https://placecats.com/neo/200/200"
)
Different notebook systems in Python may use different methods for this technique but in marimo you will only need to add a _display_
method for custom representation rendering.
More depth
If you want to learn more about how this library was made, you might enjoy our explainer of it on YouTube as well. It dives into some advanced, but fun, implementation details. Including a use-case for __getattr__
.