Type-safe, composable UI components for Python — server-side rendered, HTMX-first.
Project description
htmforge
Type-safe, composable UI components for Python — server-side rendered, HTMX-first, framework-agnostic.
Why htmforge?
- No templates — build HTML with plain Python classes and type-checked props
- HTMX-native — typed enums for every
hx-*attribute, zero string guessing - Pydantic validation — props are validated on construction and assignment
- Framework-agnostic — works with FastAPI, Flask, Django, or any WSGI/ASGI app
Installation
pip install htmforge
Quickstart
A FastAPI route that renders a full page with a user table and an add-user form:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from htmforge.components.page import Page
from htmforge.components import DataTable, FormField, InputType
from htmforge.core.element import Element
from htmforge.elements import div, h1
app = FastAPI()
USERS = [["Ada Lovelace", "ada@example.com"], ["Grace Hopper", "grace@example.com"]]
class UsersPage(Page):
users: list[list[str]]
added: bool = False
def _body_content(self) -> list[Element | str | None]:
return [
div(
h1("Users"),
DataTable(
headers=["Name", "Email"],
rows=self.users,
),
FormField(
name="name",
label_text="Full Name",
input_type=InputType.TEXT,
required=True,
),
)
]
@app.get("/users", response_class=HTMLResponse)
def list_users() -> str:
return UsersPage(
title="Users",
css_urls=["/static/style.css"],
users=USERS,
).to_html()
Components
| Component | Description | Import |
|---|---|---|
DataTable |
Table with optional HTMX reload | from htmforge.components import DataTable |
Alert |
Info/success/warning/error box, dismissible | from htmforge.components import Alert |
Pagination |
Previous/Next + page links with HTMX targeting | from htmforge.components import Pagination |
Page |
Full HTML document with DOCTYPE, abstract base | from htmforge.components.page import Page |
FormField |
Label + input + error div, 8 input types | from htmforge.components import FormField |
HTMX Integration
All HTMX attributes are available as typed enums — no string typos:
from htmforge.elements import button
from htmforge.htmx import HxSwap, HxTarget, HxTrigger
btn = button(
"Delete",
hx_delete="/users/1",
hx_swap=HxSwap.OUTER_HTML,
hx_target=HxTarget.CLOSEST_TR,
hx_confirm="Really delete?",
)
# → <button hx-delete="/users/1" hx-swap="outerHTML"
# hx-target="closest tr" hx-confirm="Really delete?">Delete</button>
Framework Support
FastAPI
from fastapi.responses import HTMLResponse
@app.get("/", response_class=HTMLResponse)
def index() -> str:
return MyPage(title="Home").to_html()
Flask
from flask import Response
@app.route("/")
def index() -> Response:
return MyPage(title="Home").to_flask()
Django
from django.http import HttpRequest, HttpResponse
def index(request: HttpRequest) -> HttpResponse:
return MyPage(title="Home").to_django()
Contributing
Contributions are welcome — please read CONTRIBUTING.md first.
License
MIT — 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file htmforge-0.1.0.tar.gz.
File metadata
- Download URL: htmforge-0.1.0.tar.gz
- Upload date:
- Size: 2.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2bcb80b479f77109c87c5a2eeb21afff5ea9b8cfd87edefdb70e9892111b65c
|
|
| MD5 |
d63301e9835a39fe26e21e0dc4369453
|
|
| BLAKE2b-256 |
9e96d5f2f7aeab1d833c7d3be542ba57e945346d3b3e1a9907f9fb6248d70eb1
|
File details
Details for the file htmforge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: htmforge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00734ec986bfd3fa3e085c82d409388ebca2f138a04ebc808e0ab9ceada67ac3
|
|
| MD5 |
0455d9bc871e05e9b18e2268eba511df
|
|
| BLAKE2b-256 |
ef4f11172ee8698e90ade4afc671a871d77dea931ec9964b40b5d6a598fde3cf
|