Backend-neutral Hyper HTML templates for Python
Project description
Hyper
Write type-safe HTML in .hyper files and import it directly from Python. Hyper compiles templates in memory, with no CLI, build step, or generated .py files.
uv add hyperhtml
Requires Python 3.10 or newer.
Render a component
Create app/templates/Greeting.hyper:
name: str
---
<h1>Hello, {name}!</h1>
Import it in a FastAPI endpoint:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from app.templates import Greeting
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def home():
return Greeting(name="World")
The response is:
<h1>Hello, World!</h1>
Hyper compiles Greeting.hyper on first import and caches it for the life of the process.
Use Django
Return a component directly from a Django view:
from django.http import HttpResponse
from app.templates import Greeting
def home(request):
return HttpResponse(Greeting(name="World"))
To call Hyper components from Django templates, install the extra:
uv add "hyperhtml[django]"
Add the app, context processor, and builtin to your existing Django settings:
INSTALLED_APPS = [
# ...
"hyperhtml.integrations.django",
]
TEMPLATES = [{
# ...
"OPTIONS": {
"context_processors": [
# ...
"hyperhtml.integrations.django.context_processors.components",
],
"builtins": [
"hyperhtml.integrations.django.templatetags.hyper",
],
},
}]
Components in Django template directories become available by name:
{% hyper Greeting name=user.first_name / %}
Use Jinja
Install the Jinja extra:
uv add "hyperhtml[jinja2]"
Add the extension to an environment with a filesystem loader:
from jinja2 import Environment, FileSystemLoader
from hyperhtml.integrations.jinja2 import HyperExtension
env = Environment(
loader=FileSystemLoader("templates"),
extensions=[HyperExtension],
)
.hyper files under templates/ become Jinja globals:
{{ Greeting(name="Ada") }}
Both Jinja and Django preserve Hyper output as safe HTML. Hyper still escapes values passed into components.
Compose components
Components compose like HTML elements:
# app/components/ProductCard.hyper
name: str
price: float
image: str
on_sale: bool = False
---
<div class={["card", {"sale": on_sale}]}>
<img src={image} alt={name} />
<h3>{name}</h3>
if on_sale:
<span class="badge">Sale</span>
end
<p class="price">${price:.2f}</p>
</div>
# app/pages/Store.hyper
from app.components import ProductCard
from app.models import Product
products: list[Product]
---
<main>
for product in products:
<{ProductCard}
name={product.name}
price={product.price}
image={product.image}
on_sale={product.on_sale}
/>
end
</main>
Use control flow
The template body accepts Python control flow. Blocks end with end:
from app.enums import Status
from app.models import Product
status: Status
products: list[Product]
---
match status:
case Status.LOADING:
<div class="spinner"></div>
case Status.ERROR:
<p class="error">Something went wrong</p>
case Status.OK:
if not products:
<p>No products found</p>
else:
for product in products:
<p>{product.name}</p>
end
end
end
Stream a response
Every component exposes its generated function as .stream:
from fastapi.responses import StreamingResponse
from app.pages import Store
@app.get("/store")
def store():
return StreamingResponse(
Store.stream(products=products),
media_type="text/html",
)
IDE support
- JetBrains: syntax highlighting, Python language injection, and compiler diagnostics
- TextMate and VS Code: syntax highlighting
Contributing
See CONTRIBUTING.md.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 hyperhtml-0.1.1.tar.gz.
File metadata
- Download URL: hyperhtml-0.1.1.tar.gz
- Upload date:
- Size: 150.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c6f9d1e2bb24fcb2186e91d30de0383cc18d57c84fe0850e016afe8e7660e02
|
|
| MD5 |
7da42400f8c18d89b1cb36cade414c79
|
|
| BLAKE2b-256 |
4e4240780e70368bc5459f95c223590d03894c6f2b63c3554fe80529d61c01f6
|
File details
Details for the file hyperhtml-0.1.1-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: hyperhtml-0.1.1-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 436.1 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5679109c280caa807ea323025377690fb09f40a90cf784b7aba7a240ee7e4d56
|
|
| MD5 |
8d804905cc21d31d4ddbbd2148437198
|
|
| BLAKE2b-256 |
0084d1b74c90c03294a1980114936bc5e26502ba978023d366f5071a879ff08a
|
File details
Details for the file hyperhtml-0.1.1-cp310-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: hyperhtml-0.1.1-cp310-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 561.1 kB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0063896c6cf01378bfa3ebea568bd880ed806e15b84d563b0cb3044e6b770fa6
|
|
| MD5 |
a1994f6a5ee12de6dccc06b9f078fbb4
|
|
| BLAKE2b-256 |
bf9750e4dc9cdc08481618be656563c2ad36192bbf1a4fdb4d868b576dcad90b
|
File details
Details for the file hyperhtml-0.1.1-cp310-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: hyperhtml-0.1.1-cp310-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 514.2 kB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26f0e0a2aeeedc4529b48bfc4382dc3329e9d65d209f71417733dc1c2e2eed13
|
|
| MD5 |
987d840b8404a5df08763d834af20ee0
|
|
| BLAKE2b-256 |
4689e3f33eab4c26d651c1682ac21434833c0314a72c5868ab8d03be0043f6fa
|
File details
Details for the file hyperhtml-0.1.1-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: hyperhtml-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 493.4 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f8ef3f0a485c16def8a41ada56601065584a651758171b8f4dd37dc33ccb61e
|
|
| MD5 |
27754d2dbf92658f1738edbfaffba5c6
|
|
| BLAKE2b-256 |
1ae7c2074e42f4037b16bafdc8a6d1261ffa86c05e2c04377cdce2935d3b4f1f
|
File details
Details for the file hyperhtml-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: hyperhtml-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 511.5 kB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd308ea8b410643f3734708e58a3a04d1d9b98f56e668a9fc58b089bdd9a2be9
|
|
| MD5 |
481cc136c1b86ac694c0c3ca7f0d5be0
|
|
| BLAKE2b-256 |
5776196398682bbb54d25af85ac4634e8316ab2e6f97590d2a6f075d413aa05e
|