Skip to main content

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

MPL-2.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

htmlforge-0.0.2.tar.gz (30.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

htmlforge-0.0.2-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

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

Hashes for htmlforge-0.0.2.tar.gz
Algorithm Hash digest
SHA256 fa1af26388d619b5a2cf46279bd54509820128b02cb5362b6b444858dcd198dc
MD5 bf5196845b15329da037cf0577805050
BLAKE2b-256 7ed8271000003ee5660cf47fb07f5fddab97e0f01cbd6a72fe89c10280adb488

See more details on using hashes here.

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

Hashes for htmlforge-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 deedd9748c79c817a15c28ddefa5d959bf2e442d097176f54ddf1e778f027e8a
MD5 8e4e1607ce796a2d13e718aef3f015c2
BLAKE2b-256 4301a102442eb5b6d20ad657a4ee3c6a6132650c8148f9ef39497442bbcb035c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 files

0.0.1

2 files

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