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.6.0.tar.gz (530.0 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.6.0-py3-none-any.whl (384.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: kida_templates-0.6.0.tar.gz
  • Upload date:
  • Size: 530.0 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.6.0.tar.gz
Algorithm Hash digest
SHA256 d01b38442cd0d2f10dfaa0215f6aeb474577596081486b23b482309bf8d68c3f
MD5 3c20fb57e4a8823bbf4aaf19a1545d06
BLAKE2b-256 bf3a07c7cdd1ff8a96ca277663cb5358a3104ee115a0b5a98a5540a82111a31c

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.6.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.6.0-py3-none-any.whl.

File metadata

  • Download URL: kida_templates-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 384.8 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.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e5da2e0531c9256e0db19b6c7afc4b9220eb426677f9b4ed0ac12ee59a56b5f3
MD5 01f7737968a300900d1eda692f315c25
BLAKE2b-256 5a074d08e9333f009cf578e557f28dfa22a190af89c4c4ac9934848528c66309

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.6.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