Back to main.

Calmcode Shorts

mohtml logomohtml

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__.


Back to main.