Skip to main content

tests Coveralls Latest Version python wheel Python Versions license

tagz

A lightweight, type-safe Python library for building and parsing HTML documents programmatically without templates.

📚 Full documentation: https://mosquito.github.io/tagz/

Overview

tagz lets you construct HTML using pure Python code with a clean, intuitive API. No template engines, no DSLs — just Python functions and objects that map directly to HTML elements.

Key Features:

  • Programmatic HTML construction — build documents using Python objects and methods
  • HTML parser — parse existing HTML strings back into manipulable Tag objects
  • Type-safe — full mypy support with comprehensive type annotations
  • Streaming support — memory-efficient rendering with iter_lines(), iter_chunk(), and iter_string()
  • Automatic escaping — XSS protection enabled by default
  • CSS helpers — built-in Style and StyleSheet objects
  • Fragments and raw — group elements without wrapper tags, or splice in pre-rendered HTML
  • Page objects — high-level API for complete HTML documents with DOCTYPE support

Installation

pip install tagz

or with uv:

uv add tagz

Requires Python 3.10+.

Quick start

from tagz import Page, StyleSheet, Style, html


page = Page(
    lang="en",
    body_element=html.body(
        html.h1("Hello"),
        html.div(
            html.strong("world"),
        ),
        html.a(
            "example link",
            html.i("with italic text"),
            href="https://example.com/"
        ),
    ),
    head_elements=(
        html.meta(charset="utf-8"),
        html.meta(name="viewport", content="width=device-width, initial-scale=1"),
        html.title("tagz example page"),
        html.link(href="/static/css/bootstrap.min.css", rel="stylesheet"),
        html.script(src="/static/js/bootstrap.bundle.min.js"),
        html.style(
            StyleSheet({
                "body": Style(padding="0", margin="0"),
                (".container", ".container-fluid"): Style(transition="opacity 600ms ease-in"),
            })
        )
    ),
)

# `pretty=False` is the fast path; pretty=True produces human-readable output.
output = page.to_html5(pretty=True)
assert output.startswith("<!doctype html>")
assert "<strong>" in output

The pretty-printed output looks like:

<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8"/>
		<meta content="width=device-width, initial-scale=1" name="viewport"/>
		<title>
			tagz example page
		</title>
		<link href="/static/css/bootstrap.min.css" rel="stylesheet"/>
		<script src="/static/js/bootstrap.bundle.min.js">
		</script>
		<style>
			body {margin: 0; padding: 0;}
			.container, .container-fluid {transition: opacity 600ms ease-in;}
		</style>
	</head>
	<body>
		<h1>
			Hello
		</h1>
		<div>
			<strong>
				world
			</strong>
		</div>
		<a href="https://example.com/">
			example link
			<i>
				with italic text
			</i>
		</a>
	</body>
</html>

Where to next?

The full documentation is organised in the Diátaxis style:

  • Tutorials — guided lessons that take you from zero to a working page, parser, or streamed document.
  • How-to guides — recipe-style answers to specific problems (streaming, callables, async data, data: URIs, CSV → table, …).
  • Reference — the full API surface with type signatures.
  • Explanation — design rationale: escaping model, callables and laziness, why there's no async render path.

Feature highlights

Feature Read more
Callable children & attributes How-to: lazy children
Conditional attributes via ABSENT How-to: conditional attributes
Boolean attributes (checked, disabled, …) How-to: boolean attributes
Custom / non-standard tag names How-to: custom tags
Fragments and unescaped Raw content How-to: fragments vs raw
Inline style= and <style> blocks How-to: inline & embedded CSS
Streaming to file / socket / ASGI How-to: stream to a socket
data: URIs for inline binary data How-to: embed binary data
Pre-resolving async data How-to: prefetch async data
Serving HTML fragments to htmx (aiohttp) How-to: htmx + aiohttp — full demo in examples/htmx-asyncio
Parsing existing HTML Tutorial: parse and modify

License

MIT — see LICENSE.

Metadata

Release files for tagz 0.8.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tagz 0.8.2
File Size Uploaded
tagz-0.8.2.tar.gz 13.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tagz 0.8.2
File Interpreter ABI Platform
tagz-0.8.2-py3-none-any.whl Python 3 none any Details

Total release size: 28.3 kB

Release files / tagz-0.8.2.tar.gz

Download URL tagz-0.8.2.tar.gz
Size 13.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1ad3c47ff296079951eab9a53050bb5874a8d9481150534479d8eafa0a141649
BLAKE2b-256 checksum
How to use checksums
ff1fc43d6554d98f6a7037aa5f898903259ca42ec3d565e7287794aaa4e506ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 16, 2026.

Transparency log

Release files / tagz-0.8.2-py3-none-any.whl

Download URL tagz-0.8.2-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
255ec249863bafee4bca5de2887c154d507770e0c866d2cf04a0715edcec7a5b
BLAKE2b-256 checksum
How to use checksums
ae80d9bc0729dea0d5d0eeb23663311a04b767ce792eebce488f5d6cc95238c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.2 This release

2 release files

0.8.0

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.6.2

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page