Skip to main content

starlette-html

starlette-html is a Python-first HTML DSL for Starlette that helps you build server-rendered UI with plain Python functions.

It gives you a simple way to:

  • build HTML in Python
  • compose reusable components with normal functions
  • pass data as regular function arguments
  • render full documents or partial fragments
  • return HTML responses directly from routes
  • keep escaping safe by default

You might also like my other Starlette packages that I use and maintain:

  • starlette-hot-reload - a lightweight hot reload utility for Starlette that provides fast in-browser reloads for templates and static files.
  • starlette-tailwindcss - a lightweight utility for Starlette that builds Tailwind CSS on startup with optional watch mode during development.

Installation

uv add starlette-html
# or
pip install starlette-html

Usage

Basic route

from starlette.applications import Starlette
from starlette.routing import Route
from starlette_html import Document
from examples.basic.pages import HomePage


async def load_user(request):
    return {"name": "Ada", "email": "ada@example.com"}


async def homepage(request):
    user = await load_user(request)
    return Document(HomePage(user=user))


app = Starlette(
    routes=[
        Route("/", homepage),
    ]
)

Layout composition

Shared layouts keep the route and page components focused on content.

from starlette_html import body, head, html, title


def BaseLayout(*children, page_title: str):
    return html(
        head(title(page_title)),
        body(*children),
    )

Then a page component can compose the layout with its own content:

from examples.basic.layouts import BaseLayout
from starlette_html import h1, p


def HomePage(*, user: dict[str, str]):
    return BaseLayout(
        h1(f"Hello {user['name']}"),
        p(user["email"]),
        page_title="Home",
    )

Core idea

The library keeps the model simple.

  • HTML tags are Python callables
  • components are plain Python functions
  • positional arguments become children
  • keyword arguments become attributes
  • lists and tuples are flattened
  • None and False children are ignored

Example:

from starlette_html import div, h1, p


def UserCard(*, name: str, email: str):
    return div(
        h1(name),
        p(email),
        cls="user-card",
    )

Rendering

Use render when you want an HTML fragment.

from starlette_html import li, ul, render


html_fragment = render(
    ul(
        li("One"),
        li("Two"),
    )
)

Use render_document when you want a full HTML document.

from starlette_html import body, h1, head, html, render_document, title


page = render_document(
    html(
        head(title("Home")),
        body(h1("Hello")),
    )
)

Route helpers

starlette-html includes thin response helpers for direct route usage.

from starlette_html import Document, HTML, body, h1, head, html, title


async def homepage(request):
    return Document(
        html(
            head(title("Home")),
            body(h1("Hello")),
        )
    )


async def fragment(request):
    return HTML(h1("Fragment"))

HTMX-friendly attributes

Normal HTML attributes work naturally, including HTMX attributes.

from starlette_html import button


button(
    "Refresh",
    hx_get="/items",
    hx_target="#items",
    hx_swap="outerHTML",
)

Safety

Dynamic text is escaped by default.

If you need to render trusted HTML, wrap it with Markup.

from starlette_html import Markup, div


div(Markup("<strong>Hello</strong>"))

License

MIT

Metadata

Release files for starlette-html 0.2.0

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

Source distribution (sdist)

Source distribution for starlette-html 0.2.0
File Size Uploaded Provenance Actions
starlette_html-0.2.0.tar.gz 5.4 kB Without provenance Details for starlette_html-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for starlette-html 0.2.0
File Interpreter ABI Platform Actions
starlette_html-0.2.0-py3-none-any.whl Python 3 none any Details for starlette_html-0.2.0-py3-none-any.whl

Total release size: 12.2 kB

Release files / starlette_html-0.2.0.tar.gz

Download URL starlette_html-0.2.0.tar.gz
Size 5.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ac2e8c323546b4f995cc2dcc32e1ed6cd2e2b10ec87860df6cf0f9b31a4da864
BLAKE2b-256 checksum
How to use checksums
b71684dfaaf24cade247db8331dc030c2d73197965c9b9f7661296a7736a5e23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / starlette_html-0.2.0-py3-none-any.whl

Download URL starlette_html-0.2.0-py3-none-any.whl
Size 6.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
77d249f5161073bab269b4eb479e45a38dff9f47549b2ec3b95187e698f29513
BLAKE2b-256 checksum
How to use checksums
255ba1551da20cb89605e4ce0f13b2c12ba9f5a3579275dc7fb82dbdecfb6f4b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for starlette-html 0.2.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

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