htmlforge
Build web pages with Python, export to HTML with a single command — like manim generates videos.
manim scene.py MyScene → mp4
htmlforge page.py MyPage → html
htmlforge script app.py → js
Installation
pip install htmlforge
Quick Start
1. Write a Python page script mysite.py
from htmlforge import Doc
page = Doc("My Site")
# Generate styles with Python kwargs (no CSS strings!)
page.style("body", background="#f5f5f5", font_family="sans-serif")
page.style(".py-card", border_radius="12px", box_shadow="0 2px 8px rgba(0,0,0,.1)")
# Build the page
page.heading("Welcome to My Site")
page.text("Built with **htmlforge**, supports *Markdown* syntax")
page.card("Features",
"40+ HTML components",
"Generate styles with Python code",
"Export HTML with one command",
)
page.table(
["Feature", "Description"],
[
["Components", "40+ HTML components"],
["Built-in theme", "Works out of the box"],
["CLI tools", "render / serve / watch / script"],
],
)
page.button("Click me", on_click="alert('Hello!')", color="#4CAF50")
2. Run the command to export HTML
# Basic render
htmlforge render mysite.py
# Specify output directory
htmlforge render mysite.py -o build
# Render and start a local server
htmlforge render mysite.py -s
# Watch for file changes and auto-rebuild
htmlforge render mysite.py -w
# Render a specific page (when file has multiple pages)
htmlforge render mysite.py MyPage
CLI Commands
| Command | Description |
|---|---|
htmlforge render <file.py> |
Render all pages to dist/ |
htmlforge render <file.py> -o <dir> |
Specify output directory |
htmlforge render <file.py> <page> |
Render only the specified page |
htmlforge render <file.py> -s |
Start HTTP server after render |
htmlforge render <file.py> -s -p 3000 |
Specify server port |
htmlforge render <file.py> -w |
Watch for changes and auto-rebuild |
htmlforge script <file.py> |
Convert Python file to JavaScript |
htmlforge script <file.py> -o app.js |
Specify output JS filename |
htmlforge script <file.py> --helpers |
Include DOM helper functions |
Doc API — Ultra Simple
Doc is a high-level API designed for Python programmers who don't know HTML. It comes with a built-in theme — no CSS required to build great-looking pages.
from htmlforge import Doc
page = Doc("Title")
# Generate styles with Python kwargs (no CSS strings!)
page.style("body", background="linear-gradient(135deg, #667eea, #764ba2)", color="white")
page.style("h1", font_size="3rem", text_align="center")
page.style(".py-card", background="rgba(255,255,255,.15)", backdrop_filter="blur(10px)")
# Content (supports **Markdown** syntax)
page.heading("Hello World")
page.text("Supports **bold**, *italic*, `code`, [links](url)")
page.card("Card Title", "Card content, **supports Markdown**")
page.list(["Item A", "Item B", "Item C"])
page.table(["Col 1", "Col 2"], [["a", "b"], ["c", "d"]])
page.button("Button", on_click="alert('hi')", color="#e74c3c")
page.input("Type here...", name="name")
page.select(["Option A", "Option B", "Option C"])
page.code("print('hello')", lang="python")
page.details("Collapsible", "Hidden content...")
page.nav(("Home", "/"), ("About", "/about"))
page.divider()
# Layout
page.row(Doc.make_card("A"), Doc.make_card("B"), Doc.make_card("C"))
JavaScript & DOM Interaction
Bind events to elements
from htmlforge import Button
btn = Button("Click me")
# Bind raw JavaScript
btn.on("click", "alert('hello')")
btn.on("mouseover", "this.style.color='red'")
# Bind Python code (auto-converted to JS)
btn.on_py("click", "print('clicked!')")
# → onclick="console.log('clicked!');"
Add JavaScript to the page
# Raw JavaScript
page.js("document.title = 'Dynamic'")
page.js("function greet() { alert('hello'); }")
# External JS file
page.js_file("app.js")
# Python code → JavaScript (auto-converted)
page.py_script('''
def greet(name):
print(f"Hello {name}")
greet("World")
''')
# Run on page load (DOMContentLoaded)
page.on_ready("console.log('Page loaded!')")
page.on_ready_py('print("Ready!")')
DOM manipulation helpers
# Get element properties (returns JS expressions)
val = page.get_attr("#input", "value") # → document.querySelector('#input').getAttribute('value')
text = page.get_text("#title") # → document.querySelector('#title').textContent
html = page.get_html("#content") # → document.querySelector('#content').innerHTML
value = page.get_value("#myInput") # → document.querySelector('#myInput').value
# Set element properties (generates JS scripts)
page.set_attr("#el", "class", "active")
page.set_text("#title", "New Title")
page.set_html("#content", "<b>bold</b>")
page.set_value("#input", "hello")
# Visibility
page.show("#modal")
page.hide("#loading")
page.toggle("#sidebar")
# CSS class manipulation
page.add_class("#el", "active")
page.remove_class("#el", "hidden")
page.toggle_class("#menu", "open")
Python → JavaScript Transpiler
Use htmlforge script to convert Python files to JavaScript:
htmlforge script app.py # → app.js
htmlforge script app.py -o out.js # → out.js
htmlforge script app.py --helpers # include DOM helpers ($, $$, getAttr, setAttr, ...)
Or use it programmatically:
from htmlforge import py_to_js, convert_file
# Convert Python source string to JS
js = py_to_js("""
def greet(name):
print(f"Hello {name}")
for i in range(10):
greet("World")
""")
# Convert a file
convert_file("app.py", "app.js")
Supported Python → JS conversions
| Python | JavaScript |
|---|---|
print(...) |
console.log(...) |
input(...) |
prompt(...) |
def f(x): |
function f(x) { |
class Foo(Bar): |
class Foo extends Bar { |
self.x |
this.x |
if/elif/else: |
if/else if/else { |
for i in range(n): |
for (let i = 0; i < n; i++) { |
for x in items: |
for (let x of items) { |
while cond: |
while (cond) { |
try/except/finally: |
try/catch/finally { |
True / False / None |
true / false / null |
and / or / not |
&& / || / ! |
a // b |
Math.floor(a / b) |
a ** b |
Math.pow(a, b) |
len(x) |
x.length |
f"Hello {name}" |
`Hello ${name}` |
lambda x: x + 1 |
(x) => x + 1 |
x in items |
items.includes(x) |
sorted(items) |
[...items].sort() |
Page API — Fine-grained Control
Use Page + the component system when you need more control:
from htmlforge import Page, H1, P, Div, Table, Button
page = Page("Title", lang="en")
page.add_css("body { font-family: sans-serif; }")
page.add(
H1("Welcome"),
P("Hello World"),
Div(class_="card").add(
H1("Features", level=2),
P("Content..."),
),
)
Element — Chainable API
div = Div(id="main", class_="wrapper")
div.add(H1("Title"), P("Content")) # Add child elements
div.css(color="red", font_size="16px") # Set inline styles (camelCase → kebab-case)
div.attr("data-id", "123") # Set attributes
div.on("click", "alert('clicked')") # Bind JS event
div.on_py("click", "print('clicked')") # Bind Python event (auto-converted)
html = div.render() # → HTML string
Components
| Category | Components |
|---|---|
| Structure | Div, Section, Header, Footer, Nav, Main, Article, Aside, Span, Container |
| Text | H1-H6, P, Strong, Em, Blockquote, Code, Pre, Small, Mark |
| Links/Media | Link, Img, Video, Audio, Iframe, Canvas |
| Lists | Ul, Ol, Li, List |
| Tables | Table, Thead, Tbody, Tr, Th, Td, Caption |
| Forms | Form, Input, Textarea, Select, Option, Checkbox, Radio, Label, Button |
| Other | Hr, Br, Text, Progress, Details, Summary |
Example: Multi-page Site
# site.py
from htmlforge import Doc
home = Doc("Home")
home.heading("Home")
home.text("Welcome to the home page")
about = Doc("About")
about.heading("About Us")
about.text("This is the about page")
blog = Doc("Blog")
blog.heading("Blog")
blog.text("Latest posts...")
htmlforge render site.py
# → dist/home.html, dist/about.html, dist/blog.html
License
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 htmlforge-0.0.2.tar.gz.
File metadata
- Download URL: htmlforge-0.0.2.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa1af26388d619b5a2cf46279bd54509820128b02cb5362b6b444858dcd198dc
|
|
| MD5 |
bf5196845b15329da037cf0577805050
|
|
| BLAKE2b-256 |
7ed8271000003ee5660cf47fb07f5fddab97e0f01cbd6a72fe89c10280adb488
|
File details
Details for the file htmlforge-0.0.2-py3-none-any.whl.
File metadata
- Download URL: htmlforge-0.0.2-py3-none-any.whl
- Upload date:
- Size: 22.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deedd9748c79c817a15c28ddefa5d959bf2e442d097176f54ddf1e778f027e8a
|
|
| MD5 |
8e4e1607ce796a2d13e718aef3f015c2
|
|
| BLAKE2b-256 |
4301a102442eb5b6d20ad657a4ee3c6a6132650c8148f9ef39497442bbcb035c
|