Module

templating.returns

Template, Fragment, Page, Stream, TemplateStream, and ValidationError return types.

Frozen dataclasses that handlers return. The content negotiation layer inspects these to dispatch to the kida renderer.

Classes

Template 4
Render a full kida template. Usage:: return Template("page.html", title="Home", items=items)

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
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
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…

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
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…

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 isNone(the default), the block name is used as the target ID.
  • SSE streams: target becomes the SSE event name. Templates usesse-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
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.…

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-Request without HX-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
def effective_page_block_name(self) -> str
Returns
str
Internal Methods 1
__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`…

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: - *…

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-Redirect to redirectURL (client-side full redirect).
  • non-htmx: 303 redirect toredirectURL.

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
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…

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
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…

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
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 %…

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
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>``…

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
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…

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
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…

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
def effective_page_block_name(self) -> str
Returns
str
Internal Methods 1
__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…

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
def __init__(self, main: Fragment | Template | Page | LayoutPage | PageComposition, /, *oob_fragments: Fragment) -> None
Parameters
Name Type Description
main
*oob_fragments