Skip to main content

Typed HTML builder with generated tag helpers.

Project description

Python License Dependencies Typing Tests Philosophy

ZenHtml

H

日本語 README

Typed HTML builder for Python. Call tag helpers in zen_html.h to build HTML directly in Python with strong typing. It runs solely on the standard library—no external dependencies. _base.py contains the rendering logic, and _generator.py autogenerates the tag API (zen_html.h) from _tag_spec.py.

pip install zenhtml

Features

  • Fully typed API: Each tag exposes common props (class_, id, name, …) plus Literal/boolean-restricted attributes. class_ itself accepts a str, any iterable of str, or None, so you can build class lists dynamically without manual joins.
  • Simple DOM composition: Nested iterables are accepted as children, so H.div(list_of_nodes) just works. Prefer keyword-argument children=[...] when you want to list props first—it produces the same result as positional children.
  • Convenient helpers: dataset dict → data-*, style dict → CSS strings, and pretty_html/pretty_dict for debugging.
  • Reusable tokens: to_token(), html_, and dict_ can be used for streaming or structured rendering.
  • HTML5 coverage: 110+ tags (metadata, forms, tables, interactive elements…) are generated from _tag_spec.py. SVG/MathML are intentionally out of scope, helping keep the library compact and focused.
  • Escaped by default: Text children/attribute values are HTML-escaped automatically. Wrap trusted fragments with H.RAW_STR() when you really need unescaped output, and keep H.strict_validation enabled to fail fast on invalid props/void-tag children.

Usage

from typing import Literal
from zen_html.h import H

page: H = H.html(
    H.head(
        H.meta(charset="utf-8"),
        H.title("Hello, H"),
    ),
    H.body(
        children=[
            H.h1("Hello"),
            H.p("Generated in Python.", class_=["lead", "muted"]),
            H.button("Click", type="button", disabled=None),
        ],
        class_="page",
    ),
    lang="ja",
)

print(page.html_)          # plain string
print(page.pretty_html())  # indented output

def button(kind: Literal["button", "submit"]) -> H:
    return H.button("Click", type=kind)

button("button")    # OK
button("invalid")   # mypy error thanks to Literal

examples/sample.py includes Starlette/FastAPI helpers (HResponse, HDocumentResponse, select) showing real-world usage. examples/pandas_pivot.py demonstrates how to turn a pandas pivot table into an HTML table (pandas is an optional dependency for that example). Run it with python -m examples.pandas_pivot to keep imports working from the repo root.

Key properties & methods

  • html_: Concatenated HTML string for the node (eager render). Suitable for templates that just need a string.
  • pretty_html(indent=0): Prints a human-readable representation, handy for debugging or inspection.
  • to_token(): Generator yielding individual HTML tokens. Use it for streaming responses (StreamingResponse, ASGI, etc.).
  • dict_: JSON-serializable tree containing tag, escaped props, and children. Useful for client-side rendering or feeding into other serializers.

Escaping & validation

  • All text nodes and attribute values are escaped automatically. If you need to inject a pre-escaped fragment, wrap it with H.RAW_STR("<span>safe</span>").
  • Runtime validation is enabled by default (H.strict_validation = True) and raises when you pass children to void tags or supply unsupported Literal/bool values. Set it to False when you prefer warnings and best-effort rendering. Validation occurs during node construction, so token streaming (to_token() / HResponse) never yields partial or invalid HTML—errors surface up front.

Rendering via dict_ in JavaScript

dict_ returns a JSON-serializable structure. You can ship it to the browser and render it there:

import json
from zen_html.h import H

payload = json.dumps(H.div("Hi", class_=["greeting", "highlight"]).dict_)
<script type="module">
  import { HRender } from "/examples/h_render.js";
  const tree = JSON.parse({{ payload | tojson }});
  document.body.appendChild(HRender(tree));
</script>

Regenerating tag API

H/h.py is generated from _tag_spec.py. After editing the spec, run:

python3 - <<'PY'
from zen_html._generator import generate_class
generate_class(output="H/h.py")
PY

Development notes

  • Tooling (Black/Isort/djlint) is configured in pyproject.toml.
  • Boolean props render only when True; False/None are ignored.
  • dataset={"fooBar": "baz"}data-foo-bar="baz"; style={"fontSize": "12px"}font-size: 12px.
  • Requires Python 3.10+ so ParamSpec-based decorators keep IDE (VS Code) completions accurate.

License

See LICENSE.

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

zenhtml-0.1.4.tar.gz (19.8 kB view details)

Uploaded Source

Built Distribution

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

zenhtml-0.1.4-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

Details for the file zenhtml-0.1.4.tar.gz.

File metadata

  • Download URL: zenhtml-0.1.4.tar.gz
  • Upload date:
  • Size: 19.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for zenhtml-0.1.4.tar.gz
Algorithm Hash digest
SHA256 7d49f571e033fb9c2d4f28fbe9a262f3e680854a81aaf807d57c2a84b622b970
MD5 09d5ab4cca1ae18b06f7e13b9e68132c
BLAKE2b-256 1a064ce1e9759b4fc6b52635d9f12bc2c5e5d9d609bad736d37a8eda5ea5a3a7

See more details on using hashes here.

File details

Details for the file zenhtml-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: zenhtml-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 15.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for zenhtml-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 5e9018ff6eacbf70e1bb5e0496f934560d4409e9a4a01066e5a4c21196aadda2
MD5 47aa1ef33be1fe77da2f44d25b437a79
BLAKE2b-256 e8428f169ab6f9e9b97f1351109f157933e115735f4423a5fe2540096744e0b6

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