Classes
Template
4
▼
Render a full kida template.
Usage::
return Template("page.html", title="Home", items=items)
Template
4
▼
Render a full kida template.
Usage::
return Template("page.html", title="Home", items=items)
Attributes
| Name | Type | Description |
|---|---|---|
name |
str
|
— |
context |
dict[str, Any]
|
— |
Methods
inline
2
InlineTemplate
▼
Create a template from a string. For prototyping only.
Usage::
return Te…
staticmethod
inline
2
InlineTemplate
▼
def inline(source: str, /, **context: Any) -> InlineTemplate
Create a template from a string. For prototyping only.
Usage::
return Template.inline("<h1>{{ title }}</h1>", title="Hello")
Parameters
| Name | Type | Description |
|---|---|---|
source |
— |
|
**context |
— |
Returns
InlineTemplate
Internal Methods 1 ▼
__init__
2
▼
__init__
2
▼
def __init__(self, name: str, /, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
**context |
— |
InlineTemplate
3
▼
A template rendered from a string source. For prototyping.
Separate type so the content negotiati…
InlineTemplate
3
▼
A template rendered from a string source. For prototyping.
Separate type so the content negotiation layer can distinguish it
from file-based templates, andapp.check()can warn about
inline templates in production code.
Attributes
| Name | Type | Description |
|---|---|---|
source |
str
|
— |
context |
dict[str, Any]
|
— |
Methods
Internal Methods 1 ▼
__init__
2
▼
__init__
2
▼
def __init__(self, source: str, /, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
source |
— |
|
**context |
— |
Fragment
6
▼
Render a named block from a kida template.
The *target* field controls how the fragment is deliver…
Fragment
6
▼
Render a named block from a kida template.
The target field controls how the fragment is delivered:
- OOB responses: target specifies the DOM element ID for the
out-of-band swap. If target is
None(the default), the block name is used as the target ID. - SSE streams: target becomes the SSE event name. Templates
use
sse-swap="{target}"to receive the fragment. If target isNone, the event name defaults to"fragment".
Usage::
return Fragment("search.html", "results_list", results=results)
With explicit OOB target::
Fragment("cart.html", "counter", target="cart-counter", count=5)
With explicit SSE event name::
yield Fragment("dashboard.html", "stats_panel",
target="stats-update", stats=stats)
# Client: <div sse-swap="stats-update">
Attributes
| Name | Type | Description |
|---|---|---|
template_name |
str
|
— |
block_name |
str
|
— |
target |
str | None
|
— |
swap |
str | None
|
— |
context |
dict[str, Any]
|
— |
Methods
Internal Methods 1 ▼
__init__
5
▼
__init__
5
▼
def __init__(self, template_name: str, block_name: str, /, *, target: str | None = None, swap: str | None = None, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
template_name |
— |
|
block_name |
— |
|
target |
— |
Default:None
|
swap |
— |
Default:None
|
**context |
— |
Page
6
▼
Render a full template or a request-aware page fragment.
Combines Template and Fragment semantics.…
Page
6
▼
Render a full template or a request-aware page fragment.
Combines Template and Fragment semantics. The content negotiation layer inspects the incoming request headers and renders:
- Full template for normal browser navigations and htmx history-restore requests.
- Named fragment block for narrow htmx fragment requests
(
HX-RequestwithoutHX-History-Restore-Request). - Page block for boosted navigations when a page needs a wider, fragment-safe root than the narrow fragment block.
This eliminates the manualif request.is_fragmentboilerplate
that every htmx-reachable route would otherwise need.
Usage::
return Page("hackernews.html", "story_list",
stories=stories, page="list")
With an explicit page-level block for boosted navigation::
return Page(
"dashboard.html",
"results_panel",
page_block_name="page_root",
stats=stats,
)
Attributes
| Name | Type | Description |
|---|---|---|
name |
str
|
— |
block_name |
str
|
— |
page_block_name |
str | None
|
— |
context |
dict[str, Any]
|
— |
Methods
effective_page_block_name
0
str
▼
Block used when a full page fragment root is required.
property
effective_page_block_name
0
str
▼
def effective_page_block_name(self) -> str
Returns
str
Internal Methods 1 ▼
__init__
4
▼
__init__
4
▼
def __init__(self, name: str, block_name: str, /, *, page_block_name: str | None = None, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
block_name |
— |
|
page_block_name |
— |
Default:None
|
**context |
— |
Action
3
▼
Represent a side-effect endpoint that should not swap response HTML.
Defaults to ``204 No Content`…
Action
3
▼
Represent a side-effect endpoint that should not swap response HTML.
Defaults to204 No Contentso htmx receives a successful response
without replacing any target content. Optional htmx response headers can
be attached for client-side behavior.
Usage::
return Action()
return Action(trigger="saved")
return Action(refresh=True)
Attributes
| Name | Type | Description |
|---|---|---|
status |
int
|
— |
trigger |
str | dict[str, Any] | None
|
— |
refresh |
bool
|
— |
FormAction
1
▼
Form success result with progressive enhancement.
Auto-negotiates htmx vs non-htmx responses:
- *…
FormAction
1
▼
Form success result with progressive enhancement.
Auto-negotiates htmx vs non-htmx responses:
- htmx + fragments: renders fragments (OOB-style) + optional
HX-Triggerheader. No redirect. - htmx + no fragments:
HX-RedirecttoredirectURL (client-side full redirect). - non-htmx: 303 redirect to
redirectURL.
Usage::
return FormAction("/contacts")
With fragments for htmx (non-htmx still gets a redirect)::
return FormAction(
"/contacts",
Fragment("contacts.html", "table", contacts=contacts),
Fragment("contacts.html", "count", target="count", count=len(contacts)),
trigger="contactAdded",
)
Methods
Internal Methods 1 ▼
__init__
4
▼
__init__
4
▼
def __init__(self, redirect: str, *fragments: Fragment, trigger: str | None = None, status: int = 303) -> None
Parameters
| Name | Type | Description |
|---|---|---|
redirect |
— |
|
*fragments |
— |
|
trigger |
— |
Default:None
|
status |
— |
Default:303
|
ValidationError
5
▼
Return a form fragment with 422 status for htmx validation.
Bundles the most common htmx form patt…
ValidationError
5
▼
Return a form fragment with 422 status for htmx validation.
Bundles the most common htmx form pattern: validate server-side, re-render the form fragment with errors on failure, return 422 so htmx knows to swap the error content.
The negotiation layer renders this as aFragmentwith status
422. If retarget is set, theHX-Retargetresponse header is
added so htmx swaps errors into a different element than the
original trigger.
Usage::
result = validate(form, rules)
if not result:
return ValidationError("form.html", "form_body",
errors=result.errors, form=form)
With retarget::
return ValidationError("form.html", "form_errors",
retarget="#error-banner",
errors=result.errors)
Attributes
| Name | Type | Description |
|---|---|---|
template_name |
str
|
— |
block_name |
str
|
— |
retarget |
str | None
|
— |
context |
dict[str, Any]
|
— |
Methods
Internal Methods 1 ▼
__init__
4
▼
__init__
4
▼
def __init__(self, template_name: str, block_name: str, /, *, retarget: str | None = None, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
template_name |
— |
|
block_name |
— |
|
retarget |
— |
Default:None
|
**context |
— |
Stream
3
▼
Render a kida template with progressive streaming.
Context values that are awaitables resolve conc…
Stream
3
▼
Render a kida template with progressive streaming.
Context values that are awaitables resolve concurrently. Each template section streams to the browser as its data arrives.
Usage::
return Stream("dashboard.html",
header=site_header(),
stats=await load_stats(),
feed=await load_feed(),
)
Attributes
| Name | Type | Description |
|---|---|---|
template_name |
str
|
— |
context |
dict[str, Any]
|
— |
Methods
Internal Methods 1 ▼
__init__
2
▼
__init__
2
▼
def __init__(self, template_name: str, /, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
template_name |
— |
|
**context |
— |
TemplateStream
3
▼
Render a template with Kida's render_stream_async.
Use when the template contains ``{% async for %…
TemplateStream
3
▼
Render a template with Kida's render_stream_async.
Use when the template contains{% async for %} or {{ await }}
and context includes async iterators consumed during rendering.
O(n) work — template yields chunks as it iterates, not re-render per item.
Usage::
return TemplateStream("chat.html",
stream=llm.stream(prompt),
prompt=prompt,
)
Attributes
| Name | Type | Description |
|---|---|---|
template_name |
str
|
— |
context |
dict[str, Any]
|
— |
Methods
Internal Methods 1 ▼
__init__
2
▼
__init__
2
▼
def __init__(self, template_name: str, /, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
template_name |
— |
|
**context |
— |
Suspense
4
▼
Render a page shell immediately, then fill in deferred blocks via OOB.
Like React's ``<Suspense>``…
Suspense
4
▼
Render a page shell immediately, then fill in deferred blocks via OOB.
Like React's<Suspense>but server-rendered. Context values that
are awaitables are deferred: the shell renders with those keys
set toNone(showing skeleton/fallback content), then each block
is re-rendered with real data and streamed as an OOB swap chunk.
For htmx navigations, blocks arrive ashx-swap-oobelements.
For initial page loads,<template> + inline <script>pairs
handle the swap without any framework.
Usage::
return Suspense("dashboard.html",
header=site_header(), # sync — in the shell
stats=load_stats(), # awaitable — deferred
feed=load_feed(), # awaitable — deferred
)
Template (uses normal conditional rendering for skeletons)::
{% block stats %}
{% if stats %}
{% for s in stats %}...{% end %}
{% else %}
<div class="skeleton">Loading stats...</div>
{% end %}
{% end %}
Block-to-DOM mapping defaults to block name = element ID. Override with defer_map::
Suspense("page.html", defer_map={"stats": "stats-panel"}, ...)
Attributes
| Name | Type | Description |
|---|---|---|
template_name |
str
|
— |
context |
dict[str, Any]
|
— |
defer_map |
dict[str, str]
|
— |
Methods
Internal Methods 1 ▼
__init__
3
▼
__init__
3
▼
def __init__(self, template_name: str, /, *, defer_map: dict[str, str] | None = None, **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
template_name |
— |
|
defer_map |
— |
Default:None
|
**context |
— |
LayoutSuspense
5
▼
Suspense with layout chain — used when Suspense is returned from mount_pages.
Carries layout metad…
LayoutSuspense
5
▼
Suspense with layout chain — used when Suspense is returned from mount_pages.
Carries layout metadata so the first chunk is wrapped in the layout shell (head, CSS, sidebar, etc.). OOB chunks target block IDs inside the page.
Attributes
| Name | Type | Description |
|---|---|---|
suspense |
Suspense
|
— |
layout_chain |
Any
|
— |
context |
dict[str, Any]
|
— |
request |
Any
|
— |
Methods
Internal Methods 1 ▼
__init__
4
▼
__init__
4
▼
def __init__(self, suspense: Suspense, layout_chain: Any, /, *, context: dict[str, Any] | None = None, request: Any = None) -> None
Parameters
| Name | Type | Description |
|---|---|---|
suspense |
— |
|
layout_chain |
— |
|
context |
— |
Default:None
|
request |
— |
Default:None
|
LayoutPage
8
▼
Render a page within a filesystem-based layout chain.
Used by ``mount_pages()`` routes. The negot…
LayoutPage
8
▼
Render a page within a filesystem-based layout chain.
Used bymount_pages()routes. The negotiation layer composes
the layout chain at the correct depth based onHX-Target:
- Full page load: render all layouts nested around the page block
- Boosted navigation: render from the targeted layout down using the page block
- Fragment request: render just the fragment block
The layout_chain and context_providers are set by the pages discovery system — handlers never construct this directly.
Usage (internal — set by the pages framework)::
return LayoutPage(
"page.html",
"content",
page_block_name="page_root",
layout_chain=chain,
context_providers=providers,
title="Home",
)
Attributes
| Name | Type | Description |
|---|---|---|
name |
str
|
— |
block_name |
str
|
— |
page_block_name |
str | None
|
— |
layout_chain |
LayoutChain | None
|
— |
context_providers |
tuple[ContextProvider, ...]
|
— |
context |
dict[str, Any]
|
— |
Methods
effective_page_block_name
0
str
▼
Block used when layouts or boosted swaps need the page root.
property
effective_page_block_name
0
str
▼
def effective_page_block_name(self) -> str
Returns
str
Internal Methods 1 ▼
__init__
6
▼
__init__
6
▼
def __init__(self, name: str, block_name: str, /, *, page_block_name: str | None = None, layout_chain: LayoutChain | None = None, context_providers: tuple[ContextProvider, ...] = (), **context: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
block_name |
— |
|
page_block_name |
— |
Default:None
|
layout_chain |
— |
Default:None
|
context_providers |
— |
Default:()
|
**context |
— |
OOB
3
▼
Compose a primary response with out-of-band fragment swaps.
htmx processes the first element as th…
OOB
3
▼
Compose a primary response with out-of-band fragment swaps.
htmx processes the first element as the normal swap target, then
scans for elements withhx-swap-ooband swaps them into the
page by ID.OOBrenders all fragments into a single HTML
response with the correct attributes.
Each OOB fragment's target ID defaults to itsblock_name
(convention), but can be overridden viaFragment(..., target="id").
Usage::
return OOB(
Fragment("products.html", "list", products=products),
Fragment("cart.html", "counter", count=new_count),
Fragment("notifications.html", "badge", unread=3),
)
The first fragment is the primary swap target. All subsequent
fragments are rendered withhx-swap-oob="true" and an id
matching their target.
Attributes
| Name | Type | Description |
|---|---|---|
main |
Fragment | Template | Page | LayoutPage | PageComposition
|
— |
oob_fragments |
tuple[Fragment, ...]
|
— |
Methods
Internal Methods 1 ▼
__init__
2
▼
__init__
2
▼
def __init__(self, main: Fragment | Template | Page | LayoutPage | PageComposition, /, *oob_fragments: Fragment) -> None
Parameters
| Name | Type | Description |
|---|---|---|
main |
— |
|
*oob_fragments |
— |