Back to list
Kabilan108

fasthtml

by Kabilan108

linux config files

0🍴 0📅 Jan 24, 2026

SKILL.md


name: fasthtml description: Build interactive web apps in pure Python using FastHTML. Use when the user wants to prototype web apps in Python without JavaScript frameworks. FastHTML combines HTMX for interactivity, Starlette for routing, and Python "FastTags" for HTML generation. Ideal for rapid prototyping with real-time updates, forms, charts, and database-backed UIs.

FastHTML Dashboard Development

FastHTML creates server-rendered hypermedia apps in pure Python. It combines Starlette (routing), HTMX (interactivity), and FastTags (HTML generation).

Key principles:

  • Prefer Python over JS; never use React/Vue/Svelte
  • Use serve() to run (no if __name__ needed)
  • Return FT components or tuples from handlers
  • Use HTMX attributes for dynamic updates without page reloads

Minimal App

from fasthtml.common import *

app, rt = fast_app()

@rt
def index():
    return Titled("Dashboard", 
        P("Welcome to the dashboard"),
        A("View Data", hx_get=data, hx_target="#content"),
        Div(id="content"))

@rt
def data():
    return Div(H2("Data Loaded"), P("Dynamic content here"))

serve()

Run: python app.py → Access at localhost:5001

FastTags (FT Components)

HTML elements as Python functions. Positional args = children, keyword args = attributes.

# Basic elements
Div(P("Hello"), cls="container")  # cls → class
Input(id="email", type="email", placeholder="Email")
Button("Submit", type="submit", disabled=False)  # False omits attr

# Special attributes
Label("Name", _for="name")  # _for → for
Div(**{'@click': "handler()"})  # dict unpacking for special chars

# Common patterns
Form(method="post", action=handler)(
    Input(name="title", placeholder="Title"),
    Button("Save"))

HTMX Interactivity

Add hx_* attributes for dynamic behavior without JavaScript:

# GET request, swap inner HTML of #results
Button("Load", hx_get=search, hx_target="#results")

# POST form, swap response into #items after existing content
Form(hx_post=create, hx_target="#items", hx_swap="beforeend")(
    Input(name="item"), Button("Add"))

# Common hx_swap values: innerHTML (default), outerHTML, beforeend, afterbegin, delete
# Trigger on events: hx_trigger="click", "change", "keyup delay:500ms"

Dashboard Layout Pattern

from fasthtml.common import *

app, rt = fast_app()

def nav(): 
    return Nav(
        A("Dashboard", href=index), 
        A("Reports", href=reports),
        A("Settings", href=settings))

def layout(*content, title="Dashboard"):
    return Title(title), Container(nav(), Main(*content))

@rt
def index():
    return layout(
        H1("Overview"),
        Grid(
            Card(H3("Users"), P("1,234"), header=None, footer=A("View all", href=users)),
            Card(H3("Revenue"), P("$45,678")),
            Card(H3("Orders"), P("89"))),
        title="Dashboard")

Database-Backed Dashboard (Fastlite)

from fasthtml.common import *
from fastlite import database

db = database('dashboard.db')

class Metric: id:int; name:str; value:float; updated:str
metrics = db.create(Metric, transform=True)

app, rt = fast_app()

@rt
def index():
    return Titled("Metrics Dashboard",
        Div(id="metrics-list")(*[metric_card(m) for m in metrics()]),
        Form(hx_post=add_metric, hx_target="#metrics-list", hx_swap="beforeend")(
            Input(name="name", placeholder="Metric name"),
            Input(name="value", type="number", placeholder="Value"),
            Button("Add Metric")))

def metric_card(m):
    return Card(H4(m.name), P(f"{m.value}"), id=f"metric-{m.id}",
        footer=Button("Delete", hx_post=delete.to(id=m.id), 
                      hx_target=f"#metric-{m.id}", hx_swap="outerHTML"))

@rt
def add_metric(metric: Metric):
    return metric_card(metrics.insert(metric))

@rt
def delete(id: int):
    metrics.delete(id)
    return ""  # Empty response removes element

serve()

Charts with Plotly

app, rt = fast_app(hdrs=[Script(src="https://cdn.plot.ly/plotly-2.32.0.min.js")])

@rt
def index():
    data = [{"x": [1,2,3], "y": [4,1,2], "type": "scatter"}]
    return Titled("Chart Dashboard",
        Div(id="chart"),
        Script(f"Plotly.newPlot('chart', {data});"))

Real-Time Updates (SSE)

from fasthtml.common import *
import asyncio

hdrs = (Script(src="https://unpkg.com/htmx-ext-sse@2.2.3/sse.js"),)
app, rt = fast_app(hdrs=hdrs)
shutdown = signal_shutdown()

@rt
def index():
    return Titled("Live Dashboard",
        Div(hx_ext="sse", sse_connect="/stream", sse_swap="message", 
            hx_swap="innerHTML", id="live-data"))

async def generate():
    import random
    while not shutdown.is_set():
        yield sse_message(Div(f"Value: {random.randint(1,100)}"))
        await asyncio.sleep(1)

@rt
async def stream(): return EventStream(generate())

serve()

Forms and Data Binding

from dataclasses import dataclass

@dataclass
class Settings: theme:str; notifications:bool; limit:int

@rt
def settings():
    form = Form(hx_post=save_settings)(
        LabelInput("Theme", name="theme"),
        CheckboxX(id="notifications", label="Enable notifications"),
        LabelInput("Limit", name="limit", type="number"),
        Button("Save"))
    return Titled("Settings", fill_form(form, current_settings))

@rt
def save_settings(s: Settings):
    # s is auto-populated from form data
    save_to_db(s)
    return Div("Settings saved!", id="message")

MonsterUI for Rich Dashboards

For production dashboards with Tailwind styling, use MonsterUI:

from fasthtml.common import *
from monsterui.all import *

app, rt = fast_app(hdrs=Theme.blue.headers())

@rt
def index():
    return Titled("Dashboard",
        Grid(
            Card(H3("Metric 1"), P("$12,345", cls=TextPresets.bold_lg)),
            Card(H3("Metric 2"), P("1,234 users")),
            Card(H3("Metric 3"), P("98.5%")), cols=3),
        Card(
            CardHeader(H3("Recent Activity")),
            CardBody(
                Table(
                    Thead(Tr(Th("User"), Th("Action"), Th("Time"))),
                    Tbody(
                        Tr(Td("Alice"), Td("Login"), Td("2m ago")),
                        Tr(Td("Bob"), Td("Purchase"), Td("5m ago")))))))

serve()

MonsterUI provides: Card, Grid, Table, Button (with ButtonT.primary/destructive), Modal, NavBar, DivFullySpaced, DivCentered, LabelInput, LabelSelect, form components, and typography presets.

Common Patterns Reference

PatternCode
Target by IDhx_target="#element-id"
Swap modeshx_swap="outerHTML", "beforeend", "afterbegin", "delete"
OOB updateDiv(id="x", hx_swap_oob="true") updates #x regardless of target
Route as hrefA("Link", href=handler) or hx_get=handler
With paramshandler.to(id=5)/handler?id=5
Confirm actionhx_confirm="Are you sure?"
Loading indicatorhx_indicator="#spinner"
Debounce inputhx_trigger="keyup changed delay:500ms"

File Structure

my_dashboard/
├── main.py          # App entry point
├── data/
│   └── app.db       # SQLite database
└── static/          # Static files (auto-served)
    └── styles.css

Quick Reference

  • fast_app() - Create app with sensible defaults (includes Pico CSS)
  • fast_app(pico=False, hdrs=[...]) - Custom headers, no Pico
  • Titled(title, *children) - Page with Title + H1 + Container
  • Card(*c, header=, footer=) - Card component
  • Grid(*divs) - CSS grid layout
  • fill_form(form, obj) - Populate form from object
  • serve() - Run uvicorn with live reload

For comprehensive API details, see references/api-reference.md.

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon