Metadata-Version: 2.4
Name: larzhtml
Version: 0.1.0
Summary: Build HTML in Python, safely: text and attributes are escaped by default (XSS-safe). Composable tag builders. Zero dependencies.
Author: larz-scripter
License: MIT
Project-URL: Homepage, https://github.com/larz-scripter/larzhtml
Project-URL: Repository, https://github.com/larz-scripter/larzhtml
Project-URL: Issues, https://github.com/larz-scripter/larzhtml/issues
Keywords: html,html-builder,xss,escaping,templating,markup,safe-html,generation,zero-dependency
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# larzhtml

**Build HTML in Python - safely. Pure Python, zero dependencies.**

Composing HTML with f-strings is how XSS holes get made. larzhtml lets you build
markup as nested Python calls where **every text child and attribute value is
HTML-escaped automatically**; you opt out explicitly with `raw()` for content you
already trust.

```python
from larzhtml import div, p, a, ul, li, raw

div(
    p("Hello ", a("world", href="https://x.com")),
    ul(*[li(x) for x in items]),
    class_="card", id="main",
)
# <div class="card" id="main"><p>Hello <a href="https://x.com">world</a></p>...</div>

div("<script>alert(1)</script>")     # -> <div>&lt;script&gt;...&lt;/script&gt;</div>
```

## Why

- **Safe by construction.** Text and attribute values are escaped by default, so
  untrusted data can't inject tags or break out of an attribute. The XSS-prone
  thing (`raw(...)`) is the one you have to ask for.
- **Just Python.** Elements are function calls; compose with loops, comprehensions,
  and conditionals - no template language, no `{% %}`. Great for emails, snippets,
  and server-rendered fragments.
- **Ergonomic attributes.** `class_`/`for_` (trailing underscore), `data_toggle`
  -> `data-toggle`, boolean attrs (`disabled=True` -> `disabled`), `None`/`False`
  omitted.
- **Zero dependencies.** No `lxml`, no `dominate`, no `markupsafe`.

## Install

```bash
pip install larzhtml
```

## Usage

```python
from larzhtml import div, p, a, img, ul, li, tag, raw, document

div(p("safe ", raw("<b>trusted</b>")), class_="box")
img(src="/logo.png", alt="Logo")                 # void: <img ...>
tag("my-widget")("content", data_id="1")          # any element
document(div("body"), title="Home", lang="en")    # full HTML5 doc
```

## Tests

```bash
python -m unittest discover -s tests -v   # 18 tests incl. XSS escaping
```

## The Larz stack

One of 30+ pure-Python, zero-dependency libraries at
[github.com/larz-scripter](https://github.com/larz-scripter) - pairs with
[larzmark](https://github.com/larz-scripter/larzmark) and
[larztemplate](https://github.com/larz-scripter/larztemplate).

## License

MIT (c) larz-scripter
