templating.returns

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

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.

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.

templating.returns

Name Type Default Description
type
qualified_name
element_type
description
source_file
line_number
is_autodoc
autodoc_element
_autodoc_template
_autodoc_url_path
_autodoc_page_type
title
doc_content_hash

Symbols on this page

function _validate_swap

Validate htmx swap strategy, allowing modifiers after base value.

Jump to symbol
class Template

Render a full kida template.

Usage::

return Template("page.html", title="Home", items=items)
Jump to symbol
class InlineTemplate

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

Jump to symbol
class Fragment

Render a named block from a kida template.

The target field controls how the fragment is delivered:

  • OOB responses: targetspecifies the DOM…
Jump to symbol
class Page

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…

Jump to symbol
class Action

Represent a side-effect endpoint that should not swap response HTML.

Defaults to204 No Contentso htmx receives a successful response without replacing any…

Jump to symbol
class MutationResult

Mutation success with progressive enhancement.

Also exported asFormAction— both names resolve to the same class. UseFormActionwhen the mutation is a…

Jump to symbol
class SignalEmit

Mutation that fans out signals and returns an empty body (default 204).

Pairs withhx-swap="none" on the triggering element. Each (name, value)tuple is…

Jump to symbol
class ValidationError

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…

Jump to symbol
class Stream

Render a kida template with progressive streaming.

When to use:All data is known upfront (or resolves quickly), but the template is large and…

Jump to symbol
class TemplateStream

Render a template with Kida's render_stream_async.

When to use: The template itself consumes an async iterator via {% async for %} or {{ await…

Jump to symbol
class Suspense

Render a page shell immediately, then fill in deferred blocks via OOB.

When to use:The page has slow data sources (DB queries, API…

Jump to symbol
class LayoutSuspense

Suspense with layout chain — used when Suspense is returned from mount_pages.

Carries layout metadata so the first chunk is wrapped in the layout…

Jump to symbol
class LayoutPage

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…

Jump to symbol
class OOB

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

Jump to symbol
alias FormAction

Alias oftemplating.returns.MutationResult

Jump to symbol
_validate_swap
function
def _validate_swap(value: str | None) -> None

Validate htmx swap strategy, allowing modifiers after base value.

Parameters

Name Type Default Description
value str | None
Template
class

Render a full kida template.

Usage::

return Template("page.html", title="Home", items=items)
InlineTemplate
class

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.

Fragment
class

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 htmx's "message"channel.

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">
Page
class

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_htmxboilerplate 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,
)

For page-directory/app-shell templates that follow Chirp's conventional page_root / page_contentblocks::

return Page.mounted("dashboard/page.html", stats=stats)
Action
class

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)
MutationResult
class

Mutation success with progressive enhancement.

Also exported asFormAction— both names resolve to the same class. UseFormActionwhen the mutation is a form submission and MutationResultfor non-form mutations (API endpoints, htmx-driven actions); the behavior is identical.

Auto-negotiates htmx vs non-htmx responses for any mutation (POST, PUT, PATCH, DELETE):

  • 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 (form submission)::

return MutationResult("/contacts")

With fragments for htmx (non-htmx still gets a redirect)::

return MutationResult(
    "/contacts",
    Fragment("contacts.html", "table", contacts=contacts),
    Fragment("contacts.html", "count", target="count", count=len(contacts)),
    trigger="contactAdded",
)

DELETE with confirmation::

return MutationResult(
    "/items",
    Fragment("items.html", "list", items=remaining),
    trigger="itemDeleted",
)
SignalEmit
class

Mutation that fans out signals and returns an empty body (default 204).

Pairs withhx-swap="none" on the triggering element. Each (name, value) tuple is emitted through the app's signal registry before the empty response is returned. DevTools surfaces the emit trace on the mutation row.

Usage::

return SignalEmit(("balance", new_balance))
return SignalEmit(
    ("balance", new_balance),
    ("notifications", notifications.snapshot()),
)
ValidationError
class

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)
Stream
class

Render a kida template with progressive streaming.

When to use: All data is known upfront (or resolves quickly), but the template is large and you want the browser to start painting before the full HTML is ready. Context awaitables resolve concurrently before streaming begins.

Not this — use TemplateStream when the template itself consumes an async iterator ({% async for %}, {{ await }}).

Not this — use Suspense when you want a shell/skeleton rendered immediately while slow data loads in the background.

Usage::

return Stream("dashboard.html",
    header=site_header(),
    stats=await load_stats(),
    feed=await load_feed(),
)
TemplateStream
class

Render a template with Kida's render_stream_async.

When to use: The template itself consumes an async iterator via {% async for %} or {{ await }}. HTML chunks stream to the browser as the iterator yields. O(n) — one pass, not re-render per item. Ideal for LLM token streaming and long async feeds.

Not this — use Stream when all data resolves upfront and you just want chunked transfer of a large template.

Not this — use Suspense when you want a shell rendered first, then slow sections filled in as out-of-band swaps.

Usage::

return TemplateStream("chat.html",
    stream=llm.stream(prompt),
    prompt=prompt,
)
Suspense
class

Render a page shell immediately, then fill in deferred blocks via OOB.

When to use: The page has slow data sources (DB queries, API calls) and you want the user to see the page shell/skeleton instantly. Deferred blocks stream in as out-of-band swaps when their data resolves. Best for dashboards, detail pages with multiple independent data sources.

Not this — use Stream when all data resolves quickly and you just want chunked transfer of a large template.

Not this — use TemplateStream when the template consumes an async iterator inline ({% async for %}).

Like React's<Suspense>but server-rendered. Context values that are awaitables are deferred: the shell renders with those keys set to theDEFERREDsentinel (showing skeleton/fallback content), then each block is re-rendered with real data and streamed as an OOB swap chunk.

The shell also sets__chirp_defer_pending__(see CHIRP_DEFER_PENDING_KEY in chirp.templating.suspense) to a frozensetof deferred context key names; deferred block re-renders use an empty frozenset. Do not use that name for your own context keys.

Templates: Use{% if stats is deferred %}for skeleton vs loaded. Bare{% if stats %} raises TypeErrorto prevent the common footgun where empty results ([], 0, "") keep skeletons visible after resolution.

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 (skeleton vs loaded — useis deferred, not {% if stats %})::

{% block stats %}
  {% if stats is deferred %}
    <div class="skeleton">Loading stats...</div>
  {% else %}
    {% for s in stats %}...{% end %}
  {% end %}
{% end %}

Block-to-DOM mapping defaults to block name = element ID. Override with defer_map::

Suspense("page.html", defer_map={"stats": "stats-panel"}, ...)

When static analysis misses blocks (e.g. deferred values passed through macro calls), list them explicitly with defer_blocks::

Suspense("page.html",
    defer_blocks=("hero_stars", "footer_stars"),
    stars=fetch_stars(),
)

If a deferred value fails after the shell is sent, the skeleton is replaced with an error indicator. Use error_block to render a custom fallback from the globalsuspense_error_template (configured viaAppConfig). When omitted, the error_block fromAppConfig.suspense_error_blockis used. If no error template is configured, a hardcoded default is used::

Suspense("page.html",
    error_block="custom_fallback",
    stats=load_stats(),
)
LayoutSuspense
class

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.

LayoutPage
class

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",
)
OOB
class

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.

FormAction
alias

Alias oftemplating.returns.MutationResult

View source · /home/runner/work/chirp/chirp/site/../src/chirp/templating/returns.py:1