Skip to main content

Python component framework for HTML — typed props, named slots, scoped state, error boundaries, zero JavaScript

Project description

)彡 Kida

PyPI version Build Status Python 3.14+ License: MIT

A Python component framework for HTML — typed props, named slots, scoped state, error boundaries, and zero JavaScript.

Kida compiles templates to Python AST, renders to HTML/terminal/markdown, and scales across cores on free-threaded Python 3.14t. Zero runtime dependencies.

Quick Start

pip install kida-templates
{% def card(title: str, variant: str = "default") %}
<article class="card card--{{ variant }}">
  <h3>{{ title }}</h3>
  <div class="actions">{% slot header_actions %}</div>
  <div class="body">{% slot %}</div>
</article>
{% end %}

{% call card("Settings", variant="elevated") %}
  {% slot header_actions %}<button>Save</button>{% end %}
  <p>Configure your preferences.</p>
{% end %}
from kida import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader("templates/"))
template = env.get_template("page.html")
html = template.render(title="Hello")

Component Model

Kida gives you the composition patterns of modern frontend frameworks, without a build step.

Feature Syntax
Typed props {% def card(title: str, count: int = 0) %}
Named slots {% slot header %} / {% slot %} (default)
Conditional slots has_slot("footer")
Scoped slots (data up) {% slot row let:item=item %}
Slot forwarding {% yield name %}
Context propagation {% provide theme = "dark" %} / consume("theme")
Error boundaries {% try %}...{% fallback error %}...{% end %}
Co-located styles {% push "styles" %} / {% stack "styles" %}
Pattern matching {% match status %}{% case "active" %}...{% end %}
Block-scoped variables {% set %} (scoped) / {% let %} (template-wide) / {% export %}

Static Validation

kida check templates/ --validate-calls
card.html:14: type: badge() param 'count' expects int, got str ("five")
dashboard.html:8: Call to 'card' — unknown params: titl

Catches unknown params, missing required params, and literal type mismatches at check time.

Component Discovery

kida components templates/

# components/card.html
#   def card(title: str, subtitle: str | None = None)
#     slots: header_actions, footer
#
# components/button.html
#   def button(label: str, variant: str = "primary")
#     slots: (none)
#
# 2 component(s) found.

Introspection API

template = env.get_template("components/card.html")
meta = template.def_metadata()
card = meta["card"]
print(card.params)           # (DefParamInfo(name='title', annotation='str', ...), ...)
print(card.slots)            # ('header_actions', 'footer')
print(card.has_default_slot) # True

Why Not Jinja2?

Jinja2 Kida
Typed parameters No param: str | None
Named slots No (caller() only) {% slot name %}
Scoped variables set leaks out of blocks set is block-scoped
Context propagation Prop drilling provide / consume
Error boundaries No {% try %}...{% fallback %}
Component styles Disconnected CSS files {% push "styles" %}
Call-site validation Runtime errors Compile-time checks
Component discovery Read every file kida components CLI
Block rendering No render_block() for HTMX partials
Streaming Limited render_stream() for chunked HTTP/SSE
Free-threading No GIL-free on Python 3.14t

Render Surfaces

One template syntax, four outputs.

HTML
from kida import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader("templates/"))
html = env.get_template("page.html").render(title="Hello")
Terminal
from kida.terminal import terminal_env

env = terminal_env()
template = env.from_string("""
{{ "Deploy Status" | bold | cyan }}
{{ hr(40) }}
{% for svc in services %}
{{ svc.name | pad(20) }}{{ svc.status | badge }}
{% end %}
""")
print(template.render(services=[
    {"name": "api", "status": "pass"},
    {"name": "worker", "status": "fail"},
]))
Markdown
from kida.markdown import markdown_env

env = markdown_env()
md = env.from_string("# {{ title }}\n\n{{ body }}").render(
    title="Report", body="All tests passed."
)
CI Reports (GitHub Action)

Turn pytest, coverage, ruff, and other tool output into step summaries and PR comments.

- uses: lbliii/kida@v0.3.3
  with:
    template: pytest
    data: results.xml
    data-format: junit-xml
    post-to: step-summary,pr-comment

Built-in templates for pytest, coverage, ruff, ty, jest, gotest, and sarif. Full action docs →


More Features

Template Inheritance
{# base.html #}
<!DOCTYPE html>
<html>
<body>{% block content %}{% end %}</body>
</html>

{# page.html #}
{% extends "base.html" %}
{% block content %}<h1>{{ title }}</h1>{% end %}
Regions (Parameterized Blocks)
{% region sidebar(current_path="/") %}
  <nav>{{ current_path }}</nav>
{% end %}

{{ sidebar(current_path="/about") }}

Regions are blocks (for render_block()) and callables (for inline use). Ideal for HTMX OOB swaps.

Pattern Matching & Null Safety
{% match status %}
{% case "active" %}Active{% case "pending" %}Pending{% case _ %}Unknown
{% end %}

{{ user.nickname ?? user.name ?? "Anonymous" }}
{{ config?.database?.host }}
{{ data ?|> parse ?|> validate ?|> render }}
Streaming & Block Rendering
# Stream chunks as they render
for chunk in template.render_stream(items=large_list):
    response.write(chunk)

# Render a single block (HTMX partials)
html = template.render_block("content", title="Hello")

# Compose layouts with pre-rendered blocks
html = layout.render_with_blocks({"content": inner_html}, title="Page")
Compile-Time Optimization
template = env.from_string(source, static_context={
    "site": site_config, "settings": app_settings,
})
html = template.render(page_title="Home", items=page_items)

67 pure filters evaluated at compile time. Dead branches removed. Component inlining for small defs with constant args. Use kida render template.html --explain to see active optimizations.

Free-Threading

All public APIs are safe under PYTHON_GIL=0 (Python 3.14t, PEP 703). Templates compile to immutable AST, rendering uses thread-local accumulators, and the Environment uses copy-on-write. Scales linearly with cores.

Framework Integration
# Flask
from kida.contrib.flask import KidaFlask
kida = KidaFlask(app)

# Starlette / FastAPI
from kida.contrib.starlette import KidaStarlette
templates = KidaStarlette(directory="templates")

# Django
TEMPLATES = [{"BACKEND": "kida.contrib.django.KidaDjango", ...}]
CLI
kida render template.txt --data context.json
kida check templates/ --validate-calls --a11y --typed
kida components templates/ --json
kida fmt templates/
kida extract templates/ -o messages.pot

The Bengal Ecosystem

Kida is part of a pure-Python stack built for 3.14t free-threading.

ᓚᘏᗢ Bengal Static site generator Docs
∿∿ Purr Content runtime
⌁⌁ Chirp Web framework Docs
=^..^= Pounce ASGI server Docs
)彡 Kida Component framework Docs
ฅᨐฅ Patitas Markdown parser Docs
⌾⌾⌾ Rosettes Syntax highlighter Docs
ᓃ‿ᓃ Milo Terminal UI framework Docs

License

MIT License — see LICENSE for details.

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

kida_templates-0.7.0.tar.gz (570.7 kB view details)

Uploaded Source

Built Distribution

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

kida_templates-0.7.0-py3-none-any.whl (400.5 kB view details)

Uploaded Python 3

File details

Details for the file kida_templates-0.7.0.tar.gz.

File metadata

  • Download URL: kida_templates-0.7.0.tar.gz
  • Upload date:
  • Size: 570.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kida_templates-0.7.0.tar.gz
Algorithm Hash digest
SHA256 81fcbc167f9754e0fc503d46ea50b4e558f0da1c468bcf28b57f670152856f65
MD5 9d8f7917e4b9bb04f6088d8bf55af9a9
BLAKE2b-256 7ed0261198d9c8667272ee87c2012fa42fea6628053e34c1ec7bf66ed147ece8

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.7.0.tar.gz:

Publisher: python-publish.yml on lbliii/kida

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kida_templates-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: kida_templates-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 400.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kida_templates-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b7b7e1061dbf21ba5ba296efcba40f003576c4428006ff4531fa5861e34dbc60
MD5 226d741754406cfba5db217c3c3c2257
BLAKE2b-256 b6fb52359cf08ed6547f03be43958af2ebfd5df2bb65cda08e68dd3e6ab6f27b

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.7.0-py3-none-any.whl:

Publisher: python-publish.yml on lbliii/kida

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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