nitrosh/nitro-ui
Build HTML with Python, not strings. Zero-dependency library with type-safe elements, method chaining, and JSON serialization.
1 stars0 forksUpdated Jan 26, 2026
npx skills add nitrosh/nitro-uiREADME
NitroUI
Build HTML with Python, not strings.
NitroUI is a zero-dependency Python library that lets you construct HTML documents using a clean, composable class-based API. No template files, no string concatenation, no runtime dependencies.
from nitro_ui import *
page = HTML(
Head(Title("Dashboard")),
Body(
Nav(
Link("Home", href="/"),
Link("Settings", href="/settings", cls="active")
),
Main(
H1("Welcome back!"),
Div(
Paragraph("You have ", Strong("3"), " new notifications."),
Button("View All", type="button", cls="btn-primary")
)
)
)
)
print(page.render(pretty=True))
Why NitroUI?
- Type-safe: IDE autocomplete and type hints for every element
- Composable: Build reusable components as Python classes
- Zero dependencies: Just Python 3.8+, nothing else
- Framework agnostic: Works with FastAPI, Django, Flask, or standalone
- Serializable: Convert to/from JSON for drag-and-drop builders
- LLM-friendly: Perfect for AI-generated interfaces
Installation
pip install nitro-ui
Claude Code Skill
Add NitroUI as a skill in Claude Code for AI-assisted HTML generation:
npx skills add nitrosh/nitro-ui
Quick Examples
HTML-like Syntax
Prefer lowercase tag names that look like real HTML? Use nitro_ui.html:
from nitro_ui.html import div, h1, p, ul, li, a, img
page = div(
h1("Welcome"),
p("This looks just like HTML!"),
ul(
li(a("Home", href="/")),
li(a("About", href="/about")),
),
img(src="hero.jpg", alt="Hero image"),
cls="container"
)
All standard HTML tags are available as lowercase functions. Python keywords use a trailing underscore: del_, input_, object_, map_.
Dynamic Content
from nitro_ui import *
def render_user_card(user):
return Div(
Image(src=user["avatar"], alt=user["name"]),
H3(user["name"]),
Paragraph(user["bio"]),
Link("View Profile", href=f"/users/{user['id']}"),
cls="user-card"
)
users = [
{"id": 1, "name": "Alice", "bio": "Backend engineer", "avatar": "/avatars/alice.jpg"},
{"id": 2, "name": "Bob", "bio": "Frontend developer", "avatar": "/avatars/bob.jpg"},
]
grid = Div(*[render_user_card(u) for u in users], cls="user-grid")
Method Chaining
from nitro_ui import *
card = (Div()
.add_attribute("id", "hero")
.add_styles({"background": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)", "padding": "4rem"})
.append(H1("Ship faster with NitroUI"))
.append(Paragraph("Stop fighting with templates. Start building.")))
Reusable Components
from nitro_ui import *
class Card(HTMLElement):
def __init__(self, title, *children, **kwargs):
super().__init__(**{**kwargs, "tag": "div"})
self.add_attribute("class", "card")
self.append(H3(title, cls="card-title"))
for child in children:
self.append(child)
class Alert(HTMLElement):
def __init__(self, message, variant="info", **kwargs):
super().__init__(**{**kwargs, "tag": "div"})
self.add_attributes([("class", f"alert alert-{variant}"), ("role", "alert")])
self.append(Paragraph(message))
# Usage
page = Div(
Alert("Your changes have been saved.", variant="success"),
Card("Statistics",
Paragraph("Total users: 1,234"),
Paragraph("Active today: 89")
)
)
External Stylesheets with Themes
from nitro_ui import *
from nitro_ui.styles import CSSStyle, StyleSheet, Theme
# Use a preset theme
theme = Theme.modern()
stylesheet = StyleSheet(theme=theme)
# Register component styles
btn = stylesheet.register("btn", CSSStyle(
background_color="var(--color-primary)",
color="var(--color-white)",
padding="var(--spacing-sm) var(--spacing-md)",
border_radius="6px",
border="none",
cursor="pointer",
_hover=CSSStyle(background_color="var(--color-primary-dark)")
))
# Use in your HTML
page = HTML(
Head(
Title("Styled Page"),
Style(stylesheet.render())
),
Body(
Button("Click Me", cls=btn)
)
)
Framework Integration
FastAPI
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from nitro_ui import *
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
async def home():
return HTML(
Head(Title("FastAPI + NitroUI")),
Body(H1("Hello from FastAPI"))
).render()
Flask
from flask import Flask
from nitro_ui import *
app = Flask(__name__)
@app.route("/")
def home():
return HTML(
Head(Title("Flask + NitroUI")),
Body(H1("Hello from Flask"))
).render()
Django
from django.http import HttpResponse
from nitro_ui import *
def home(request):
r
...
Publisher
Statistics
Stars1
Forks0
Open Issues0
LicenseBSD 3-Clause "New" or "Revised" License
CreatedNov 15, 2025