Skip to main content

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.

PyPI PyPI - Python Version PyPI - License image

Installation

pip install nitro-ui

AI Assistant Integration

Add NitroUI knowledge to your AI coding assistant:

npx skills add nitrosh/nitro-ui

This enables AI assistants like Claude Code to understand NitroUI and generate correct HTML code.

Quick Examples

from nitro_ui import *

page = HTML(
    Head(Title("Dashboard")),
    Body(
        Nav(
            Anchor("Home", href="/"),
            Anchor("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
  • Secure by default: Automatic HTML escaping, CSS injection prevention, tag/attribute validation
  • SVG-aware: Correct camelCase attribute handling for SVG elements
  • LLM-friendly: Perfect for AI-generated interfaces

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"]),
        Anchor("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(Component):
    tag = "div"
    class_name = "card"

    def template(self, title: str):
        return [
            H3(title, cls="card-title"),
            Slot()  # children go here
        ]

class Alert(Component):
    tag = "div"
    class_name = "alert"

    def template(self, message: str, variant: str = "info"):
        self.add_attribute("class", f"alert-{variant}")
        self.add_attribute("role", "alert")
        return [Paragraph(message), Slot()]

# Usage
page = Div(
    Alert("Your changes have been saved.", variant="success"),
    Card("Statistics",
        Paragraph("Total users: 1,234"),
        Paragraph("Active today: 89")
    )
)

Components support named slots for complex layouts:

class Modal(Component):
    tag = "div"
    class_name = "modal"

    def template(self, title: str):
        return [
            Div(H2(title), Slot("actions"), cls="modal-header"),
            Div(Slot(), cls="modal-body"),
            Div(Slot("footer"), cls="modal-footer")
        ]

# Named slots via kwargs
Modal("Confirm Delete",
    Paragraph("Are you sure?"),
    actions=Button("×", cls="close"),
    footer=[Button("Cancel"), Button("Delete", cls="danger")]
)

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):
    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
    ])

Form Builder

Generate HTML5 forms with validation using the Field class:

from nitro_ui import *

form = Form(
    Field.email("email", label="Email", required=True),
    Field.password("password", label="Password", min_length=8),
    Field.select("country", ["USA", "Canada", "Mexico"], label="Country"),
    Field.checkbox("terms", label="I agree to the Terms", required=True),
    Button("Sign Up", type="submit"),
    action="/register"
)

Field types: text, email, password, url, tel, search, textarea, number, range, date, time, datetime_local, select, checkbox, radio, file, hidden, color. See SKILL.md for full API.

HTMX Integration

Build interactive UIs without JavaScript. NitroUI converts hx_* kwargs to hx-* attributes automatically:

from nitro_ui import *

# Live search
Input(
    type="text",
    hx_get="/search",
    hx_trigger="keyup changed delay:300ms",
    hx_target="#results"
)

# Delete with confirmation
Button(
    "Delete",
    hx_delete="/items/1",
    hx_confirm="Are you sure?",
    hx_swap="outerHTML"
)

# Load more
Button("Load More", hx_get="/items?page=2", hx_target="#list", hx_swap="beforeend")

All HTMX attributes are supported: hx_get, hx_post, hx_put, hx_delete, hx_target, hx_swap, hx_trigger, hx_confirm, hx_indicator, hx_boost, and more. See SKILL.md for the complete reference.

Raw HTML Partials

Embed raw HTML for trusted content like analytics tags:

from nitro_ui import Head, Meta, Title, Partial

Head(
    Meta(charset="utf-8"),
    Partial("""
        <!-- Google Analytics -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=GA_ID"></script>
        <script>
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'GA_ID');
        </script>
    """),
    Title("My Page")
)

# Or load from a file (lazy-loaded at render time)
Partial(file="partials/analytics.html")

Warning: Partial bypasses HTML escaping. Only use with trusted content.

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

Import all elements with from nitro_ui import *:

Module Elements
nitro_ui.tags.html HTML, Head, Body, Title, Meta, Link, Script, Style, Base, Noscript, IFrame, Template, Svg, Math
nitro_ui.tags.layout Div, Section, Article, Header, Nav, Footer, Main, Aside, Details, Summary, Dialog, Address, Hgroup, Search, Menu
nitro_ui.tags.text H1-H6, Paragraph, Span, Strong, Em, Bold, Italic, Anchor (alias: Href), Code, Pre, Blockquote, Br, Wbr, Bdi, Bdo, Ruby, Rt, Rp, Data, and more
nitro_ui.tags.form Form, Input, Button, Select, Option, Textarea, Label, Fieldset, Legend, Optgroup, Output, Progress, Meter, Datalist
nitro_ui.tags.lists UnorderedList, OrderedList, ListItem, DescriptionList, DescriptionTerm, DescriptionDetails
nitro_ui.tags.media Image, Video, Audio, Source, Track, Picture, Figure, Figcaption, Canvas, Embed, Object, Param, Map, Area
nitro_ui.tags.table Table, TableRow, TableHeader, TableBody, TableFooter, TableHeaderCell, TableDataCell, Caption, Col, Colgroup

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)
  • HTML5 boolean attributes (disabled, checked, required, etc.) render correctly: True renders as a bare attribute, False omits it, None omits it
  • SVG camelCase attributes are supported via snake_case kwargs: view_box renders as viewBox, preserve_aspect_ratio as preserveAspectRatio, etc.

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 SKILL.md for a complete technical reference including method signatures, all tags, and common patterns.

Development

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

# Run tests
pytest

# Format
black src/ tests/

Ecosystem

License

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

Metadata

Release files for nitro-ui 1.0.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nitro-ui 1.0.11
File Size Uploaded
nitro_ui-1.0.11.tar.gz 85.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nitro-ui 1.0.11
File Interpreter ABI Platform
nitro_ui-1.0.11-py3-none-any.whl Python 3 none any Details

Total release size: 139.9 kB

Release files / nitro_ui-1.0.11.tar.gz

Download URL nitro_ui-1.0.11.tar.gz
Size 85.7 kB
Tags Source
SHA-256 checksum
How to use checksums
bf76452446eba1031bd1c39da57d9a2ff19495e3153cb1aa9b5e829cefaa99b5
BLAKE2b-256 checksum
How to use checksums
60ef66cf23d23e83900abf7fa0b94acb8ff74364cb507f2c1a38fc2d5c8673b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / nitro_ui-1.0.11-py3-none-any.whl

Download URL nitro_ui-1.0.11-py3-none-any.whl
Size 54.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7e5a5c77a83cae0dd31dc4a158c1b328c672386132790310f720f21e80fd16f1
BLAKE2b-256 checksum
How to use checksums
175432a06b68e5afa871b9ddabe312908a95757b7e9205714e78530cc3b85a9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.0.11 This release

2 release files

1.0.10

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release 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