Skip to main content

Build HTML with Python, not strings. Zero-dependency library with type-safe elements, method chaining, and JSON serialization.

Project description

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", class_name="active")
        ),
        Main(
            H1("Welcome back!"),
            Div(
                Paragraph("You have ", Strong("3"), " new notifications."),
                Button("View All", type="button", class_name="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"),
    class_name="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']}"),
        class_name="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], class_name="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, class_name="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", class_name=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):
    return HttpResponse(HTML(
        Head(Title("Django + NitroUI")),
        Body(H1("Hello from Django"))
    ).render())

Core Features

Pretty Printing

# Compact output (default) - ideal for production
page.render()

# Indented output - ideal for debugging
page.render(pretty=True)

JSON Serialization

Perfect for drag-and-drop builders, undo/redo, or API communication:

from nitro_ui import *
from nitro_ui.core.element import HTMLElement

# Serialize
json_data = page.to_json(indent=2)

# Deserialize
restored = HTMLElement.from_json(json_data)

HTML Parsing

Import existing HTML into NitroUI for manipulation:

from nitro_ui import from_html

element = from_html('<div class="card"><h1>Hello</h1></div>')
element.append(Paragraph("Added with NitroUI"))

Fragments

Group elements without a wrapper tag:

from nitro_ui import *

def table_rows(items):
    return Fragment(*[
        TableRow(TableDataCell(item["name"]), TableDataCell(item["price"]))
        for item in items
    ])

CSS Style Helpers

div = Div("Content")
div.add_style("color", "blue")
div.add_styles({"padding": "20px", "margin": "10px"})
div.remove_style("margin")
color = div.get_style("color")  # "blue"

Available Elements

PascalCase imports (from nitro_ui import *):

Module Elements
nitro_ui.tags.html HTML, Head, Body, Title, Meta, Script, Style, HtmlLink, IFrame
nitro_ui.tags.layout Div, Section, Article, Header, Nav, Footer, Main, Aside, Dialog
nitro_ui.tags.text H1-H6, Paragraph, Span, Strong, Em, Link, Code, Pre, Blockquote
nitro_ui.tags.form Form, Input, Button, Select, Option, Textarea, Label, Fieldset
nitro_ui.tags.lists UnorderedList, OrderedList, ListItem, DescriptionList
nitro_ui.tags.media Image, Video, Audio, Figure, Canvas, Picture, Source
nitro_ui.tags.table Table, TableRow, TableHeader, TableBody, TableHeaderCell, TableDataCell

Lowercase HTML-like imports (from nitro_ui.html import *):

Category Aliases
Document html, head, body, title, meta, script, style, link
Layout div, section, article, header, nav, footer, main, hr
Text h1-h6, p, span, strong, em, a, code, pre, b, i
Form form, input_, button, select, option, textarea, label
Lists ul, ol, li, dl, dt, dd
Media img, video, audio, figure, canvas, picture, source
Table table, tr, td, th, thead, tbody, tfoot

Note: input_, del_, object_, map_ use trailing underscore to avoid Python keyword/builtin conflicts.

Element API

Manipulation

  • append(*children) / prepend(*children) - Add children
  • clear() - Remove all children
  • clone() - Deep copy element
  • find_by_attribute(attr, value) - Find child by attribute

Attributes

  • add_attribute(key, value) / add_attributes(list)
  • get_attribute(key) / has_attribute(key)
  • remove_attribute(key)

Styles

  • add_style(prop, value) / add_styles(dict)
  • get_style(prop) / remove_style(prop)

Output

  • render(pretty=False) - Generate HTML string
  • to_json() / from_json() - JSON serialization
  • to_dict() / from_dict() - Dictionary conversion

All manipulation methods return self for chaining.

For AI/LLM Integration

NitroUI is designed to work seamlessly with AI code generation. See LLM_GUIDE.md for a complete technical reference including exact method signatures, type hints, and common patterns.

Development

# Setup
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest

# Format
black src/ tests/

License

BSD 3-Clause License. See LICENSE for details.

Links

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

nitro_ui-1.0.3.tar.gz (51.1 kB view details)

Uploaded Source

Built Distribution

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

nitro_ui-1.0.3-py3-none-any.whl (31.2 kB view details)

Uploaded Python 3

File details

Details for the file nitro_ui-1.0.3.tar.gz.

File metadata

  • Download URL: nitro_ui-1.0.3.tar.gz
  • Upload date:
  • Size: 51.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for nitro_ui-1.0.3.tar.gz
Algorithm Hash digest
SHA256 fff9ea1902db1dea0ad9c05e401dad17ca44e7006819d05294c9528d1d4f4e5d
MD5 8931b54ddb1e6c2f88e87257ad4de3d2
BLAKE2b-256 5a0094da363f080e76ea485a0c83ef31a0c983c798a73223e6fd41bbd4f3f48e

See more details on using hashes here.

File details

Details for the file nitro_ui-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: nitro_ui-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 31.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for nitro_ui-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 a60f21e705880e24955bfa80ef45fb7a60d7624613fbcc86852f7581e3d204b3
MD5 f061426fe8493b4d27a41d0400466256
BLAKE2b-256 713f4eec154cce699a3c4f662573d880876c2c09eb760a64381537892b53a9da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page