Skip to main content

Rust-backed framework for building websites in pure Python

Project description

ztml

A Rust-backed framework for building websites in pure Python. ZTML allows you to define HTML/CSS/JS using only Python expressions with as much autocompletion support as I could reasonably add. Inspired by FastHTML.

Install

pip install ztml

HTML

Every HTML element has a corresponding constructor function. Attributes are set via chained builder methods. Call render() to get an HTML string.

from ztml import *

page = render(
    Html(
        Head(Meta().charset("utf-8"), Title("My App")),
        Body(
            H1("Hello, ztml!"),
            P("Build websites with Python.").cls("intro"),
            A("GitHub").href("https://github.com").target("_blank"),
        ),
    )
)

Attributes chain naturally:

Div(
    Input().type("text").name("q").placeholder("Search...").autofocus(),
    Button("Go").type("submit"),
).cls("search-box").id("search")

Use Fragment to group elements without a wrapper tag, and Raw to inject unescaped HTML:

Fragment(
    H1("Title"),
    P("Paragraph"),
    Raw("<hr/>"),
)

Style

Build CSS with Rule, Media, Keyframes, and Frame. Wrap them in Style() to render a <style> block.

Style(
    Rule("body").margin("0").font_family("system-ui, sans-serif"),
    Rule(".container").display("flex").gap("1rem").padding("2rem"),
    Rule(".container > .sidebar").width("250px").flex_shrink("0"),
    Rule(".container > .main").flex("1"),

    Media("max-width: 768px",
        Rule(".container").flex_direction("column"),
        Rule(".container > .sidebar").width("100%"),
    ),

    Keyframes("fadeIn",
        Frame("from").opacity("0").transform("translateY(-10px)"),
        Frame("to").opacity("1").transform("translateY(0)"),
    ),

    Rule(".card").animation("fadeIn 0.3s ease-out"),
)

CSS property methods are generated from W3C specs — every standard property is available with autocompletion. Use .prop("custom-property", "value") for anything not covered.

Inline styles work too:

Div("styled").style(InlineStyle().color("red").font_weight("bold"))

Script

Build JavaScript with On event handlers and RawJs. Wrap them in Script() to render a <script> block.

Script(
    On.click("#increment", """
        let count = document.getElementById('count');
        count.textContent = parseInt(count.textContent) + 1;
    """),

    On.document_ready("console.log('page loaded')"),

    On.submit("#my-form", """
        event.preventDefault();
        alert('submitted!');
    """),

    RawJs("function greet(name) { alert('Hello, ' + name); }"),
)

Available event helpers: On.click, On.submit, On.change, On.input, On.keydown, On.keyup, On.mouseover, On.mouseout, On.focus, On.blur, On.document_ready, and On.event for custom events.

Custom Components

Any Python object with a __ztml_render__ method can be used as a renderable component. The method should return a ztml element.

class Card:
    def __init__(self, title, body):
        self.title = title
        self.body = body

    def __ztml_render__(self):
        return Div(
            H2(self.title),
            P(self.body),
        ).cls("card")

# Use directly in render()
print(render(Card("Hello", "World")))

# Or nest inside other elements
page = Div(
    Card("First", "Some content"),
    Card("Second", "More content"),
).cls("cards")

Putting It Together

A complete page with HTML, CSS, and JS:

from ztml import *

def page():
    return Html(
        Head(
            Meta().charset("utf-8"),
            Title("Counter"),
            Style(
                Rule("body").font_family("system-ui").display("flex")
                    .justify_content("center").padding("4rem"),
                Rule("button").padding("0.5rem 1rem").font_size("1.2rem")
                    .cursor("pointer").border_radius("4px"),
                Rule("#count").font_size("3rem").margin("1rem 0"),
            ),
        ),
        Body(
            H1("Counter"),
            P("0").id("count"),
            Button("Increment").id("increment"),
            Script(
                On.click("#increment", """
                    let el = document.getElementById('count');
                    el.textContent = parseInt(el.textContent) + 1;
                """),
            ),
        ),
    )

print(render(page()))

Server

ztml includes a built-in server for HTMX-powered apps, built on Starlette and Uvicorn.

from ztml import *
from ztml.server import rt, serve

@rt('/')
def get():
    return Html(
        Head(Title("Counter")),
        Body(
            H1("Counter"),
            P("0").id("count"),
            Button("Increment").hx_post("/increment").hx_target("#count"),
        ),
    )

count = 0

@rt('/increment')
def post():
    global count
    count += 1
    return P(str(count)).id("count")

serve()  # localhost:5001

Key features:

  • Method inference — the HTTP method is inferred from the function name (get, post, put, delete, etc.)
  • Auto HTMX — full-page responses (<html>) get the HTMX script auto-injected
  • Path parameters@rt('/greet/{name}') extracts name as a function argument
  • Request access — add a request parameter to access the Starlette Request object
  • Element rendering — handlers return ztml elements, automatically rendered to HTML

Building from Source

Prerequisites: Rust toolchain, Python 3.12+, uv.

# Install dependencies and build the Rust extension
uv sync

# For iterative development (faster rebuilds)
uv run maturin develop

# Generate .pyi type stubs for autocompletion
cargo run --bin gen_stubs --no-default-features

To build a distributable wheel:

maturin build --release
# Output in target/wheels/

Examples

# Generate a static HTML page to stdout 
uv run examples/static_page.py > page.html # (open page.html in your browser!)

# HTMX counter app (localhost:5001)
uv run examples/counter_server.py

# Custom components demo
uv run examples/components.py > components.html

# HTMX todo app (localhost:5001)
uv run examples/todo_server.py

Running Tests

uv run python -m pytest

# Rust unit tests
cargo test -p ztml-core

How codegen works

build.rs reads HTML element definitions from webtags and CSS property specs from w3c/webref, stored in specs/. From these it generates:

  • Element constructors — one Python function per HTML tag
  • CSS property methods — on Rule, InlineStyle, and Frame
  • Enum classes — for CSS keyword values and HTML attribute values

Releasing

CI runs on every push to main and on tags matching v*.

Regular push (tests only):

git push

Publishing a new version (build + publish to PyPI):

  1. Bump the version in crates/ztml-core/Cargo.toml and crates/ztml-python/Cargo.toml
  2. Commit, tag, and push:
git add -A && git commit -m "bump version to 0.x.y"
git tag v0.x.y
git push && git push origin v0.x.y

The v* tag triggers the full build matrix (Linux, macOS, Windows) and publishes wheels to PyPI via trusted publishing.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ztml-0.1.3-cp314-cp314-win_amd64.whl (1.1 MB view details)

Uploaded CPython 3.14Windows x86-64

ztml-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

ztml-0.1.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.6 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64

ztml-0.1.3-cp314-cp314-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

ztml-0.1.3-cp314-cp314-macosx_10_12_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

ztml-0.1.3-cp313-cp313-win_amd64.whl (1.2 MB view details)

Uploaded CPython 3.13Windows x86-64

ztml-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ztml-0.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

ztml-0.1.3-cp313-cp313-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

ztml-0.1.3-cp313-cp313-macosx_10_12_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

ztml-0.1.3-cp312-cp312-win_amd64.whl (1.2 MB view details)

Uploaded CPython 3.12Windows x86-64

ztml-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ztml-0.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

ztml-0.1.3-cp312-cp312-macosx_11_0_arm64.whl (1.5 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

ztml-0.1.3-cp312-cp312-macosx_10_12_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

File details

Details for the file ztml-0.1.3-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: ztml-0.1.3-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ztml-0.1.3-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 24c5cd694892f6d1ab9e9ce44a84863592b419b20af5be69091418726a49aac7
MD5 1e6c0dec25c9f9b9e9b5fd9eeb9aac6d
BLAKE2b-256 936f8e0b12bc1aa3de7c027889da9fbe808e3a5d73326818e46c5214b78ab02c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp314-cp314-win_amd64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 be651116f5cb3cc4113909dbc8dad47deb3f9bf185213e2ab2266353f57414a7
MD5 1383bd5fbe3e26c9eaa6f36bceddc1ca
BLAKE2b-256 dc5c0af9af75971df0b653ba80b6beecb5943f907a0d7cc7e8f4007630117eac

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 7ee78a80c6bf7f992b6424ae5ee96f9333b3cdad607ad75ec7d7d51afb6fb559
MD5 0429b5a2d4bb7e4b3e36f559fea9b3ac
BLAKE2b-256 71003ba1f9f707118e40ff780f514012c2b56351175ce01d396029cac917970e

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2290fd4dcf2838d55e3959e3bf50525dbe777ca2c51e5e9091e57411c178490e
MD5 e89a786e833300d33bcaad583e707615
BLAKE2b-256 10d97a91f1b15c95b3948bcac96129058554409c45bfba23132ddb2c339b5f1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 932909d08adb2bdb707d707638ef72250c4fe371954de2322079097f51132664
MD5 ed07f0f0341cb19936490b2986f147f1
BLAKE2b-256 b833a92f93c75b5d90727406842d9ad034715ef085c1e3cba304f53aa1275126

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp314-cp314-macosx_10_12_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: ztml-0.1.3-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ztml-0.1.3-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 b5484c419bda9d456c4b70bd9ca70ac10cdb7690c2c51449d4c08b1868a6729f
MD5 094b5dcc919dfd593a7730f6c9382b84
BLAKE2b-256 ca0b25f81ba275136b27a1f4d7048516324d2e5698a0c06450025f4e7ac85895

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp313-cp313-win_amd64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 50537695278447b0e486f8a521857f7c60e9841bebd6cda971a59ab7b5be6624
MD5 57841f7d0d305ab7aa276a187ee9b6b5
BLAKE2b-256 207a5e77a955b9b46425e2e05da5e1552b61d941267e8021a03950ab9122d488

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 19f5b6a719d099c0afa1af10162e60304c3f7aa6d7bf4b90735d1492d6d6a43b
MD5 176969e4381d53689892cd96c4c49100
BLAKE2b-256 987d52cc973009b49bc14b763b43f2eb2403a9b6e62222c2a1571676e7cc4eb5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2b1492525550986ed5a6b5246bb30651d13180f1e918967c6b83ad032672f4fc
MD5 bdb10d92a3492a9ae55ba1ac9e54fb9f
BLAKE2b-256 bf5dd7351ac041cce6359dc15ae61aa1998804c89e6393c59521f1c949bd38ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 571a687c2eb656eb0128b3591d0eba4795e8bad4c93282ec73d65d2ce939c661
MD5 35e79c8b056ab20b101cdf24dd41aae3
BLAKE2b-256 ea884b8066fc684561bda42ff97d61d55e3edb41892099ff69020163f5ab79c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp313-cp313-macosx_10_12_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: ztml-0.1.3-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ztml-0.1.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 48d8c405c1a2f7f66763db0e5af231a45d79010ed7c4a62418384a4287232326
MD5 a6679ec53bd47e23000bc766f46a1619
BLAKE2b-256 590f293605ca8d56415ad94e0f81fa5358782e5e4c5028435aeac542c651b900

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp312-cp312-win_amd64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6c40ca25d560d6f6892678961a713c9dda72f8ad19e2a6ac8e1961f11b60bc66
MD5 55cbc2bcd17b12e391a21d1aa96223e6
BLAKE2b-256 d3b139c24cd7781e0f990a1a36c8dd304cec9c7a9a30f6271ff71c383263a8e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cb3917e4b1aa693f47de6611269e995164713f96eba2ecbab20857d8b3340d67
MD5 9c978dfe62ab3e891450e2d8add6aece
BLAKE2b-256 1dd10e7908bf563cee658c9f4e3f62c3f2ec70c7612e804a875c6dae8508f69a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c4d7b459afac0c176602927bebf553eba5d89de94bff709d118d6e0e58a49b65
MD5 bdec4e9832f4e2596344941445854c62
BLAKE2b-256 e31a3362fc053d96d3303e2f8110552dd873a2732ae998a17c32bb5c98622f56

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ztml-0.1.3-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ztml-0.1.3-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f361adf44f214da194bec81ea6a9cc257f2319a7c85b932bb55afd3650c6c7a2
MD5 9c59771bb8d95e5b84a188453fd64f85
BLAKE2b-256 815223e6823e337dcd32921eeb8335a9d0a712c563e63292d15828fab0b5cffe

See more details on using hashes here.

Provenance

The following attestation bundles were made for ztml-0.1.3-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: ci.yml on bleemesser/ztml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page