Toast
Use CToastRegion once near the end of an application root. It owns a persistent visible queue, polite and assertive announcers, remaining-time pause, action/dismiss semantics, and F6 focus access. Arrival never steals focus.
Toast at a glance
Intent controls presentation; priority independently controls announcement urgency.
Show code
from typing import Any
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastAtAGlance(Component):
template = """
<section class="toast-sampler">
<p>These initial messages demonstrate presentation intent separately from urgency.</p>
<c-CToastRegion c-items="items" c-duration_ms="0" c-limit="5" />
</section>
"""
def template_data(self, kwargs: Any, slots: Any) -> dict[str, object]: # noqa: ARG002
return {
"items": tuple(
citry_ui.CToastMessage(id=intent, title=title, intent=intent)
for intent, title in (
("neutral", "Draft retained"),
("info", "Sync started"),
("success", "Field note saved"),
("warn", "Connection is slow"),
("error", "Upload failed"),
)
)
}
css = ":where(.toast-sampler) { min-block-size:20rem; padding:1rem; }"
preview = ToastAtAGlance()
preview # noqa: B018
Drive a reactive queue
Pass an Array of plain client message records. A stable id is queue identity. Remove IDs in onDismiss so expired or dismissed messages can later begin a fresh episode.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ReactiveToastQueue(Component):
template = """
<section class="toast-example" x-data="{notices: [], next: 1}">
<c-CButton @click="notices = [...notices, {
id: `note-${next}`, title: `Observation ${next++} queued`, intent: 'info'
}]">Add notification</c-CButton>
<c-CToastRegion $c-props="{
items: notices,
onDismiss: id => notices = notices.filter(item => item.id !== id),
}" />
</section>
"""
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ReactiveToastQueue()
preview # noqa: B018
<c-CToastRegion
$c-props="{
items: notices,
onDismiss: (id) => notices = notices.filter(item => item.id !== id),
}"
/>
Replace and deduplicate by ID
A retained ID updates in place. A material update restarts its lifetime and announces the replacement once; a byte-equivalent snapshot does neither.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastReplacement(Component):
template = """
<section class="toast-example" x-data="{progress: 20}">
<c-CButton @click="progress = Math.min(100, progress + 20)">Advance upload</c-CButton>
<c-CToastRegion c-duration_ms="0" $c-props="{items: [{
id: 'upload', title: `Upload ${progress}% complete`, description: 'Aurora Ridge photos'
}]}" />
</section>
"""
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ToastReplacement()
preview # noqa: B018
Pause remaining lifetime
The default lifetime is eight seconds. Set duration_ms=0 for persistent messages. Hover, focus within, document visibility, and an unrelated modal pause remaining time rather than starting a new timeout.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class TimedToast(Component):
template = """
<section class="toast-example" x-data="{items: []}">
<c-CButton @click="items = [{id: crypto.randomUUID(), title: 'Hover or focus to pause'}]">
Start timed Toast
</c-CButton>
<c-CToastRegion c-duration_ms="4000" $c-props="{
items,
onDismiss: id => items = items.filter(item => item.id !== id),
}" />
</section>
"""
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = TimedToast()
preview # noqa: B018
Add one persistent action
onAction runs before action-caused dismissal. Set closeOnAction: false when the result should remain visible.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class PersistentToastAction(Component):
template = """
<section class="toast-example" x-data="{items: [], result: 'No action yet'}">
<c-CButton @click="items = [{
id: 'offline', title: 'Working offline', actionLabel: 'Retry',
closeOnAction: false, durationMs: 0, intent: 'warn'
}]">Show persistent action</c-CButton>
<output x-text="result"></output>
<c-CToastRegion $c-props="{
items,
onAction: () => result = 'Retry requested',
onDismiss: id => items = items.filter(item => item.id !== id),
}" />
</section>
"""
css = ":where(.toast-example) { display:grid; gap:.75rem; min-block-size:16rem; padding:1rem; }"
preview = PersistentToastAction()
preview # noqa: B018
Limit the visible stack
Only the first limit unsuppressed messages render, announce, and run timers. Queued records start when promoted.
Show code
from typing import Any
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastVisibleLimit(Component):
template = """
<section class="toast-example">
<p>Dismiss a visible message to promote the queued third item.</p>
<c-CToastRegion c-items="items" c-limit="2" c-duration_ms="0" />
</section>
"""
def template_data(self, kwargs: Any, slots: Any) -> dict[str, object]: # noqa: ARG002
return {
"items": tuple(
citry_ui.CToastMessage(id=f"queue-{index}", title=f"Queue item {index}") for index in range(1, 4)
)
}
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ToastVisibleLimit()
preview # noqa: B018
Reach notifications with F6
Unmodified F6 moves from the application to the first presented Toast. F6 inside returns to the recorded element. Tab remains ordinary and is never trapped.
Show code
from typing import Any
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastFocusAccess(Component):
template = """
<section class="toast-example">
<p>Focus this page, then press F6 to enter the notification and F6 again to return.</p>
<c-CButton>Focus before F6</c-CButton>
<c-CToastRegion c-items="items" c-duration_ms="0" />
</section>
"""
def template_data(self, kwargs: Any, slots: Any) -> dict[str, object]: # noqa: ARG002
return {"items": (citry_ui.CToastMessage(id="f6", title="F6 reaches this message"),)}
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ToastFocusAccess()
preview # noqa: B018
Pause behind a modal
A global Region becomes hidden, inert, and paused while an unrelated native modal is open. Use CAlert inside the modal for feedback that must be immediate there.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastModalPause(Component):
template = """
<section class="toast-example" x-data="{items: [{id:'global', title:'Global queue waits', durationMs:0}]}">
<c-CDialog>
<c-fill name="activator" data="{ activator_attrs }">
<c-CButton c-attrs="activator_attrs">Open modal task</c-CButton>
</c-fill>
<c-fill name="title">Modal-local feedback</c-fill>
<c-fill name="default">
<c-CAlert intent="info">Use Alert for immediate feedback inside this task.</c-CAlert>
</c-fill>
</c-CDialog>
<c-CToastRegion $c-props="{items}" />
</section>
"""
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ToastModalPause()
preview # noqa: B018
Choose a logical corner
Placements are block-start-start, block-start-end, block-end-start, and block-end-end. Logical edges follow direction and writing mode.
Show code
from typing import Any
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class ToastPlacementRtl(Component):
template = """
<section class="toast-example" dir="rtl">
<p>Logical start follows this RTL context.</p>
<c-CToastRegion c-items="items" placement="block-end-start" c-duration_ms="0" />
</section>
"""
def template_data(self, kwargs: Any, slots: Any) -> dict[str, object]: # noqa: ARG002
return {"items": (citry_ui.CToastMessage(id="rtl", title="Logical start placement"),)}
css = ":where(.toast-example) { min-block-size:16rem; padding:1rem; }"
preview = ToastPlacementRtl()
preview # noqa: B018
Customize the surface
Use documented variables and part selectors. Unlayered application CSS wins; safe-area, narrow viewport, forced-colors, and print behavior stay owned.
Show code
from typing import Any
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class CustomizedToast(Component):
template = """
<section class="toast-theme">
<c-CToastRegion class_="polar-toast" c-items="items" c-duration_ms="0" />
</section>
"""
def template_data(self, kwargs: Any, slots: Any) -> dict[str, object]: # noqa: ARG002
return {
"items": (
citry_ui.CToastMessage(
id="polar",
title="Polar archive synchronized",
description="A scheme-aware brand adaptation.",
intent="success",
),
)
}
css = """
:where(.toast-theme) { color-scheme:light dark; min-block-size:16rem; padding:1rem; }
:where(.polar-toast) {
--cui-toast-background: light-dark(#eef8fb, #102a34);
--cui-toast-foreground: light-dark(#17343e, #e6f7fb);
--cui-toast-border-color: light-dark(#76b7c7, #5ea5b6);
--cui-toast-radius: 1.25rem;
}
"""
preview = CustomizedToast()
preview # noqa: B018
Composition boundaries
Toast is brief global feedback, not a task surface, form-error relationship, arbitrary card renderer, or dismissible overlay. Use CAlert for persistent rich content, CDialog/CDrawer for tasks, and Field/Form errors beside their controls. V1 deliberately has no slots, imperative service, swipe, portal, or multi-action layout.
API reference
Inputs
CToastRegion server inputs
Server inputs are passed in a template through <c-CToastRegion ... /> or in Python through CToastRegion(...).
| Input | Type | Default | Effect |
|---|---|---|---|
items | Sequence[CToastMessage] | "()" | Ordered initial queue copied and validated once per render. |
id | str | None | generated | Sets exact Region identity and generated message relationships. |
label | non-empty str | "Notifications" | Names the Region. |
messages | CToastMessages | None (CToastMessages) | None | Overrides catalog-backed dismiss and action-announcement patterns per field. |
placement | "block-start-start" | "block-start-end" | "block-end-start" | "block-end-end" (CToastPlacement) | "block-end-end" | Selects a logical viewport corner. |
limit | int (1..10) | 3 | Limits simultaneously presented messages. |
duration_ms | int | 8000 | Sets default lifetime; zero is persistent and nonzero values are 1000..120000 milliseconds. |
pause_on_hover | bool | True | Pauses remaining time while the viewport is hovered. |
pause_on_focus | bool | True | Pauses remaining time while focus is inside. |
pause_on_hidden | bool | True | Pauses remaining time while the owner document is hidden. |
class_ | str | Mapping[str, bool] | Sequence[CClassValue] | None (CClassValue) | None | Merges consumer classes onto the Region. |
style | str | Mapping[str, str | int | float | bool | None] | Sequence[CStyleValue] | None (CStyleValue) | None | Merges consumer inline styles onto the Region. |
attrs | Mapping[str, object] | None | None | Adds allowed native and data attributes without replacing owned semantics, focus, live regions, or structure. |
CToastRegion client inputs
Client inputs are passed in the browser through the $c-props="{ ... }" attribute on <c-CToastRegion />.
| Input | Type | Omitted behavior | Effect |
|---|---|---|---|
items | Array<CToastClientMessage> | Uses the copied server snapshot. | Reconciles the complete ordered queue by canonical ID. |
placement | "block-start-start" | "block-start-end" | "block-end-start" | "block-end-end" (CToastPlacement) | Uses the server fallback. | Updates logical viewport placement. |
limit | integer (1..10) | Uses the server fallback. | Changes visible capacity and promotes or queues messages. |
durationMs | integer | Uses the server fallback. | Sets default lifetime for messages without an override. |
pauseOnHover | boolean | Uses the server fallback. | Controls hover pause. |
pauseOnFocus | boolean | Uses the server fallback. | Controls focus pause. |
pauseOnHidden | boolean | Uses the server fallback. | Controls document-visibility pause. |
onDismiss | function | Does not notify a component callback. | Receives timeout, explicit-dismiss, and action-dismiss completion. |
onAction | function | Does not notify a component callback. | Receives the optional action before action-caused dismissal. |
Slots
-
Events
Component events are callback inputs supplied through $c-props. Native browser events remain available through Alpine @... attributes.
CToastRegion events
| Event | Signature | Trigger and timing | Detail | Controlled and cancellation behavior |
|---|---|---|---|---|
onDismiss | (id: string, detail: CToastDismissDetail) => void (CToastDismissDetail) | A presented message expires, is explicitly dismissed, or closes after its action. | {reason: "timeout" | "dismiss" | "action", source: Element, message: CToastClientMessage} (CToastDismissDetail) | Fires once after runtime removal; a producer should remove the ID to end suppression. |
onAction | (id: string, detail: CToastActionDetail) => void (CToastActionDetail) | The optional action Button activates. | {source: HTMLButtonElement, message: CToastClientMessage} (CToastActionDetail) | Fires before an action-caused dismissal; stale work stops if the callback removes the Region. |
Methods
-
CSS
CSS variables to theme the components. Set them on an ancestor or the component itself.
CToastRegion CSS variables
Apply these variables to CToastRegion or one of its ancestors.
| Variable | Type | Purpose | Default |
|---|---|---|---|
--cui-toast-inline-offset | length | Logical viewport inline offset. | 1rem |
--cui-toast-block-offset | length | Logical viewport block offset. | 1rem |
--cui-toast-gap | length | Visible stack gap. | 0.75rem |
--cui-toast-width | length | Preferred visible width. | 22rem |
--cui-toast-background | color | Message background. | Canvas |
--cui-toast-foreground | color | Message foreground and controls. | CanvasText |
--cui-toast-border-color | color | Message boundary. | Subtle CanvasText mix. |
--cui-toast-shadow | shadow | Message elevation. | 0 1rem 3rem rgb(15 23 42 / 22%) |
--cui-toast-radius | length | Message corners. | 0.75rem |
--cui-toast-padding | length | Message padding. | 1rem |
--cui-toast-accent | color | Neutral message accent. | currentColor |
--cui-toast-z-index | integer | Nonmodal application stacking hint. | 1000 |
Attributes
HTML attributes defined on the components that you can refer to for CSS, inspection, and testing. Read-only.
CToastRegion attributes
| Attribute | Element | Type | Meaning |
|---|---|---|---|
data-placement | Region | logical placement | Mirrors the effective viewport corner. |
data-paused | Region | present | absent | Present while timers are paused by hover, focus, visibility, or modality. |
data-intent | Toast | neutral | info | success | warn | error | Mirrors presentation intent. |
data-priority | Toast | polite | assertive | Mirrors announcement urgency. |
Selectors
Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.
CToastRegion selectors
| Selector | Element | Purpose |
|---|---|---|
[data-citry-ui-part="region"] | Region section | Viewport and attrs destination. |
[data-citry-ui-part="announcer-polite"] | Hidden live region | Serialized polite announcements. |
[data-citry-ui-part="announcer-assertive"] | Hidden live region | Serialized assertive announcements. |
[data-citry-ui-part="toast"] | Presented group | Focusable message surface. |
[data-citry-ui-part="content"] | Content wrapper | Title and optional description. |
[data-citry-ui-part="title"] | Title | Visible accessible name. |
[data-citry-ui-part="description"] | Description | Optional relationship text. |
[data-citry-ui-part="actions"] | Controls wrapper | Optional action and dismissal layout. |
[data-citry-ui-part="action"] | Button | Optional one-action control. |
[data-citry-ui-part="dismiss"] | Button | Explicit message dismissal. |
Interfaces
Aliases and data shapes referenced above.
Input type aliases
| Interface | Definition |
|---|---|
CClassValue | str | Mapping[str, bool] | Sequence[CClassValue] |
CStyleValue | str | Mapping[str, str | int | float | bool | None] | Sequence[CStyleValue] |
CToastIntent | Literal["neutral", "info", "success", "warn", "error"] |
CToastPlacement | Literal["block-start-start", "block-start-end", "block-end-start", "block-end-end"] |
CToastPriority | Literal["polite", "assertive"] |
CToastMessage
| Field | Type | Default | Meaning |
|---|---|---|---|
id | str | - | Unique canonical queue identity. |
title | str | - | Visible and accessible plain-text name. |
description | str | None | - | Optional plain supporting text. |
intent | CToastIntent | - | Presentation intent independent from urgency. |
priority | CToastPriority | - | Polite or assertive announcement channel. |
duration_ms | int | None | - | Optional per-message lifetime; zero is persistent. |
action_label | str | None | - | Optional one-action Button label. |
close_on_action | bool | - | Whether action completion dismisses the message. |
dismissible | bool | - | Whether explicit dismissal is available. |
CToastMessages
| Field | Type | Default | Meaning |
|---|---|---|---|
dismiss_label | str | None | None | Overrides the catalog-backed dismiss pattern and must contain {title}. |
action_announcement | str | None | None | Overrides the catalog-backed action announcement and must contain {action_label}. |
CToastClientMessage
| Field | Type | Default | Meaning |
|---|---|---|---|
id | string | - | Unique canonical queue identity. |
title | string | - | Visible and accessible plain-text name. |
description | string | null | - | Optional supporting text. |
intent | CToastIntent | - | Presentation intent. |
priority | CToastPriority | - | Announcement channel. |
durationMs | integer | null | - | Optional lifetime override. |
actionLabel | string | null | - | Optional one-action label. |
closeOnAction | boolean | - | Whether action dismisses. |
dismissible | boolean | - | Whether explicit dismissal is available. |
CToastDismissDetail
| Field | Type | Default | Meaning |
|---|---|---|---|
reason | "timeout" | "dismiss" | "action" | - | Runtime removal reason. |
source | Element | - | Browser source associated with dismissal. |
message | CToastClientMessage | - | Canonical public message snapshot. |
CToastActionDetail
| Field | Type | Default | Meaning |
|---|---|---|---|
source | HTMLButtonElement | - | Activated action Button. |
message | CToastClientMessage | - | Canonical public message snapshot. |
Translation keys
Catalog keys used by this family. An explicit component input or slot listed in Override takes precedence over the catalog for that instance.
CToastRegion translation keys
| Key | Purpose | Variables | Override | Browser updates |
|---|---|---|---|---|
citry-ui-toast-region | Names the notification region. | None | label input | $c-tr updates aria-label. |
citry-ui-toast-dismiss | Names each toast dismiss control. | title: str | messages.dismiss_label | $c-tr handles initial items; i18n.bind() handles browser-created items. |
citry-ui-toast-action-available | Announces that the toast exposes an action. | action_label: str | messages.action_announcement | One-shot i18n.tr() when the toast is added. |