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.

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

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

Running Tests

uv run 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

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 Distribution

ztml-0.1.0.tar.gz (54.8 kB view details)

Uploaded Source

Built Distributions

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

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

Uploaded CPython 3.14Windows x86-64

ztml-0.1.0-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.0-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.0-cp314-cp314-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

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

Uploaded CPython 3.14macOS 10.12+ x86-64

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

Uploaded CPython 3.13Windows x86-64

ztml-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ztml-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

ztml-0.1.0-cp313-cp313-macosx_11_0_arm64.whl (1.5 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

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

Uploaded CPython 3.13macOS 10.12+ x86-64

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

Uploaded CPython 3.12Windows x86-64

ztml-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ztml-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

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

Uploaded CPython 3.12macOS 11.0+ ARM64

ztml-0.1.0-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.0.tar.gz.

File metadata

  • Download URL: ztml-0.1.0.tar.gz
  • Upload date:
  • Size: 54.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.12.6

File hashes

Hashes for ztml-0.1.0.tar.gz
Algorithm Hash digest
SHA256 956acc68906e5ad738d52c6fb66aa89d79390ff0060d105c70da2dbcb745cbe5
MD5 43bdceea16179701af5d4132980bcda0
BLAKE2b-256 778b6bba455a4ec769251e238c5edae4b9c7655675ef7e0b19def6449e16d0ab

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ztml-0.1.0-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: maturin/1.12.6

File hashes

Hashes for ztml-0.1.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 3c880ca424a2313976d56986ed23a3e35d05927f1325d6de7eb1b8b41f6219b2
MD5 3989ca714ef492eef4dea7ed61c22e2e
BLAKE2b-256 a3f7530f062a814588fa0e991951f5cba6b941211e29d645a53848619acdbb72

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 548e1fb9eca042e38b3ba1e4d9b59cae525e1f442e2533438ef84fd90b59224c
MD5 8a6aa043a7a54c76db3793838058cfed
BLAKE2b-256 97355b49302e6388725144f40f922a24798fa95705d1587b10309d0ce515cc8c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 264117a7c79ecc2a0a1fe84c43aecac642114f7c64685cf851b756b64521ccf7
MD5 261d58f0049876dc2afb7568514556f3
BLAKE2b-256 734e03cb7a797797d34e593e2e3107e9145f7d5ea68adbabb47d03631ed8907d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8b242ce9ddaede2c82c53872bce2be7874e98099bf84ed5e30f12f07c7bfa4fe
MD5 81b0da86782ace3d13c7ff4e2db4e3f8
BLAKE2b-256 972e0c0fdce1951d0fe13a7e3a12def717f20f13d7e2b3dfd3b2756d26191cbe

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 fa6bd93e2438a8851f09a89d19b628f058640df7d6765d7d0c2616b71641d591
MD5 9e20f56c2267a651100eb42a0d829d84
BLAKE2b-256 58a23b21e78dd84a78a6dee9742670d6198426a0549828a4e580cf8e3dcfa808

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ztml-0.1.0-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: maturin/1.12.6

File hashes

Hashes for ztml-0.1.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 27143f8d74d285680b953f76a8ffb05ad13ceeee77a50e7e27beb0cecea429d6
MD5 46debc26f3bb5face8c98f151929cff1
BLAKE2b-256 3fc851931f749ca5e403703dff2f7ca6c150a845bbbe9646d7f9768714347a51

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3f54089b15f4fe6bdd0a480020ea063bc90a098cde43945e6fbe9aabb601ab3e
MD5 90633fa3f6a9213e9002fed4b4c471f5
BLAKE2b-256 8083ce0b561ef06d51703c2b2508b1e30e93b8259f0e42137b79736cbc18aea8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c1bfa01d12c2d2d1f2135edda2df7f82e5f00f05dd47449b7a516ef70c3ed2d1
MD5 ff80b21bd2018c89cfc7f7ce712afe80
BLAKE2b-256 bb57ce0ea38d9f5dd033efb4c94f5801915ddadab0bbf6e3fefb9f27e539b9b3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5c58911ea8b728eecb08e85d35c5b8c15dc93a10745a537e0983d276c7090542
MD5 678b114a395d4fbd4bfed24a4c181617
BLAKE2b-256 37fc4f2cd3d525994fbca65b9da612a00199916d32009cbc71fdd6f4b6418593

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e10766de3e3dfe2e5c169d36382b848bfeb6a6a6373a929b3c2768d09b59acb0
MD5 a03f38af70cb59a58c01b7e1046e7e3f
BLAKE2b-256 63e4026470f8ccc5d5a3bbadbc11a611c59e2e248a1ee6258572833ccef6df00

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ztml-0.1.0-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: maturin/1.12.6

File hashes

Hashes for ztml-0.1.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 84a51cb7f020ee016508f0f1dd2bccbfa9e68d676bed27c1ee8f61fd44dcb87e
MD5 da77da1a394046fdf65bb06708200d51
BLAKE2b-256 df04661150f846ef58fb58832019e231bf0638fff1264cbb5da4f5a53ec67bf6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e9fde366d2b8c0491cf06a89de33c4b498e3e4908cafe2e3134a07b1746dd37f
MD5 53c7939645dce6cc4833113f5061394a
BLAKE2b-256 4c6cbc1e429e794335027e4f0332a6409a71676c3650ab7373189357c68e5e14

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f471e701e0d00f74b48737e95f1cd708e26e125294965382842aec927c50f978
MD5 bacba3d0910b1c283497e43c13c45f98
BLAKE2b-256 13913f0bbb5c5f463cb4d01ee3aab72e0ef6b89abffce86c62bc3abc9c40d0d5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bf630b8b17c47a12da888ab3ed68b7bafe8b23cd998b63fd29080239ef93990c
MD5 609cd7dceda571e75742343e3e19e9a0
BLAKE2b-256 8b0b78a170a6d457bb2a2ee3d4f4dc9653ece61694ce150cc9036a2a79a1befa

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ztml-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f786867734fbe13483146e5dbe1ec76200cbe39e29bff6146daf3e0dec616098
MD5 876aa022443a5df69b2d656b99345868
BLAKE2b-256 6fcdc9b4a3c20e1cc5bfdc2a08d44386210336c747c4a0318fe599e108c8e283

See more details on using hashes here.

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