Skip to main content

Server-side components for Python with typed props, named slots, and static validation — no npm or build step

Project description

)彡 Kida

PyPI version Build Status Python 3.14+ License: MIT

Server-side components for Python — no npm, no build step.

Kida brings typed props, named slots, static call-site validation, scoped state, and error boundaries to pure-Python templates. Components render to HTML, Markdown, terminal output, and CI reports on free-threaded Python 3.14t, with no runtime dependencies.

Quick Start

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

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

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

Static Validation

Kida catches component mistakes before a user sees a page, report, or terminal screen.

{% def badge(count: int, label: str) %}
<span class="badge">{{ count }} {{ label }}</span>
{% enddef %}

{{ badge(count="five", lable="Messages") }}
kida check templates/ --strict --validate-calls
templates/dashboard.html:5: K-CMP-001: Call to 'badge' — unknown params: lable; missing required: label
templates/dashboard.html:5: K-CMP-002: type: badge() param 'count' expects int, got str ('five')

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

Use Kida For

Surface What Kida gives you
Web apps Component templates for Flask, FastAPI, Django, Chirp, and Bengal
Static sites Reusable layouts, slots, typed content components, and scoped state
CI reports Markdown step summaries and PR comments from pytest, coverage, ruff, ty, and more
Terminal tools ANSI-aware tables, badges, panels, dashboards, and progress output
Framework tooling Template metadata, block rendering, component discovery, and dependency analysis

Component Model

Kida brings frontend-style composition to ordinary Python templates.

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 %}...{% endtry %}
Co-located styles {% push "styles" %} / {% stack "styles" %}
Pattern matching {% match status %}{% case "active" %}...{% endmatch %}
Block-scoped variables {% set %} (scoped) / {% let %} (template-wide) / {% export %}

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

Render Surfaces

One template syntax can target HTML, terminal output, Markdown, and CI reports.

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 }}
{% endfor %}
""")
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
  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, sarif, release notes, and AMP agent reports. Full action docs →

Designed For Python 3.14t

Kida does not rely on the GIL for correctness. Templates compile to immutable Python code, render state lives in ContextVar, and environment mutation uses copy-on-write patterns. Public APIs are safe under PYTHON_GIL=0 on free-threaded Python 3.14t.

Why Kida?

Traditional templates Kida
Typed parameters Usually no param: str | None
Named slots Usually no {% slot name %}
Scoped variables Often leak or surprise set is block-scoped
Context propagation Prop drilling provide / consume
Error boundaries Rare {% 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 Framework-specific render_block() for HTMX partials
Streaming Varies render_stream() and render_stream_async()
Free-threading Not usually designed for it GIL-free on Python 3.14t

Advanced Features

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

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

{{ 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
{% endmatch %}

{{ 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)

Pure filters can be evaluated at compile time, dead branches can be removed, and small components with constant args can be inlined. Use kida render template.html --explain to see active optimizations.

Framework Integration
# Flask
from kida.contrib.flask import init_kida, render_template
kida_env = init_kida(app)

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

# Django
TEMPLATES = [{"BACKEND": "kida.contrib.django.KidaTemplates", ...}]
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

Status

Kida is pre-1.0 and used standalone, through mainstream Python frameworks, and across the broader Python rendering stack. The API can still move, but the core design goals are stable: pure Python, static validation, render-surface parity, and free-threaded safety.

Upgrading

Moving from 0.6.x? See the Upgrade to 0.7 tutorial for the strict_undefined=True migration patterns.

Moving from 0.7.x? See the Upgrade to 0.8 tutorial for the Mapping behavior change in null-safe access (?. and ?[...]).

Moving from 0.8.x? See the 0.9 release notes for the Markdown escaping and | safe trust-boundary changes.

Moving from 0.9.x? See the 0.10 release notes for structured diagnostics and source-attribution hardening.

Moving from 0.10.x? See the 0.11 release notes for framework quickstarts, release hardening, and internal compiler modularization.

Python Components Ecosystem

Kida is the component layer in a broader pure-Python stack built for 3.14t free-threading. Bengal remains a supported legacy integration, but no longer defines the stack's product direction.

ᓚᘏᗢ Bengal Legacy static-site integration 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.11.0.tar.gz (612.1 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.11.0-py3-none-any.whl (426.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: kida_templates-0.11.0.tar.gz
  • Upload date:
  • Size: 612.1 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.11.0.tar.gz
Algorithm Hash digest
SHA256 106dace9de272ee7af6577d6b4c439dd8be143acf8721c937366f84991d7f1a7
MD5 ad1bd2f41246bcb701aba510578578dc
BLAKE2b-256 b923b1db649aa88a1a2a8e3e2fd8f0aa6f1975799311754a56b8202b24c467b8

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: kida_templates-0.11.0-py3-none-any.whl
  • Upload date:
  • Size: 426.6 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.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e8a874eebd5bc42669343b077bb14b7c38e8b24fba83ac4800c4261520eb3e9e
MD5 cc7311047035e017e9124621444136e7
BLAKE2b-256 82a0cd7571802488cb837f98600f17baca0c72d56c70cd1dea7becb77dccd43c

See more details on using hashes here.

Provenance

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