Drop the container once on your page, typically in your base layout. It registers a global Alpine store, listens on the window for a toast event and renders a stack in each corner.
<c-ui.toast.container />
{% cotton ui.toast.container /%}
To raise a toast, dispatch a browser toast CustomEvent whose detail describes the notification. Anything it omits falls back to the container's props.
Any code can fire a toast. There are three common ways:
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', variant: 'success' } }))
$dispatch inside any component (Alpine events bubble to the window, where the container listens):
$dispatch('toast', { message: 'Saved', variant: 'success' })
HX-Trigger response header (HTMX re-dispatches it as a window event):
HX-Trigger: {"toast": {"message": "Saved", "variant": "success"}}
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', variant: 'success' } }))">
Vanilla JS
</c-ui.button>
<div x-data>
<c-ui.button x-on:click="$dispatch('toast', { message: 'Saved', variant: 'success' })">
Alpine $dispatch
</c-ui.button>
</div>
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', variant: 'success' } }))" %}
Vanilla JS
{% endcotton %}
<div x-data>
{% cotton ui.button x-on:click="$dispatch('toast', { message: 'Saved', variant: 'success' })" %}
Alpine $dispatch
{% endcotton %}
</div>
The variant sets the contextual colour and icon: info, success, warning or error. Add an optional title for a bold heading above the message.
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Heads up, a new version is available.', variant: 'info' } }))">
Info
</c-ui.button>
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved successfully', variant: 'success' } }))">
Success
</c-ui.button>
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Your trial ends soon.', variant: 'warning' } }))">
Warning
</c-ui.button>
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Could not connect to the server.', variant: 'error' } }))">
Error
</c-ui.button>
<c-ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { title: 'Invitation sent', message: 'Your teammate will receive an email shortly.', variant: 'success' } }))">
With title
</c-ui.button>
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Heads up, a new version is available.', variant: 'info' } }))" %}
Info
{% endcotton %}
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved successfully', variant: 'success' } }))" %}
Success
{% endcotton %}
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Your trial ends soon.', variant: 'warning' } }))" %}
Warning
{% endcotton %}
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Could not connect to the server.', variant: 'error' } }))" %}
Error
{% endcotton %}
{% cotton ui.button onclick="window.dispatchEvent(new CustomEvent('toast', { detail: { title: 'Invitation sent', message: 'Your teammate will receive an email shortly.', variant: 'success' } }))" %}
With title
{% endcotton %}
Three visual treatments, set per toast with appearance or as the container default. soft (default) is a tinted panel, solid is a filled colour and outline is a bordered panel on a plain surface.
{# Per toast #}
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', variant: 'success', appearance: 'solid' } }))
{# Or as the container default for every toast #}
<c-ui.toast.container appearance="solid" />
{# Per toast #}
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', variant: 'success', appearance: 'solid' } }))
{# Or as the container default for every toast #}
{% cotton ui.toast.container appearance="solid" /%}
Six anchor points, set per toast with position or as the container default: top-right (default), top-left, top-center, bottom-right, bottom-left and bottom-center. Bottom stacks grow upward so the newest toast is always nearest the edge. Try each below.
{# Per toast #}
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', position: 'bottom-center' } }))
{# Or as the container default #}
<c-ui.toast.container position="bottom-center" />
{# Per toast #}
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Saved', position: 'bottom-center' } }))
{# Or as the container default #}
{% cotton ui.toast.container position="bottom-center" /%}
For one-off styling beyond the built-in appearances, pass a class in the event detail. It is appended to that toast, so any Tailwind utilities you add win over the defaults.
window.dispatchEvent(new CustomEvent('toast', {
detail: {
title: 'Custom',
message: 'Fully restyled toast',
class: '!bg-zinc-900 !border-zinc-700 !text-white'
}
}))
Return an HX-Trigger response header naming the toast event. HTMX re-dispatches it as a window event with the JSON value as the event detail, which the container catches automatically.
import json
from django.http import HttpResponse
def delete_item(request, pk):
# ... delete the item ...
response = HttpResponse(status=204)
response["HX-Trigger"] = json.dumps({
"toast": {"message": "Item deleted", "variant": "error"}
})
return response
| Name | Description | Type | Options | Default |
|---|---|---|---|---|
position |
Default anchor for toasts that do not specify their own position. | str |
top-righttop-lefttop-centerbottom-rightbottom-leftbottom-center
|
top-right |
appearance |
Default visual treatment for toasts that do not specify their own appearance. | str |
softsolidoutline
|
soft |
duration |
Default auto-dismiss time in milliseconds. Use 0 for a sticky toast. Overridable per toast. | int | — | 4000 |
class |
Additional classes merged onto each toast stack wrapper. | str | — |
Fire a window CustomEvent named toast. Its detail object accepts:
| Name | Description | Type | Options | Default |
|---|---|---|---|---|
message |
The toast body text (required for a useful toast). | str | — | |
variant |
Contextual colour and icon. | str |
infosuccesswarningerror
|
info |
appearance |
Visual treatment for this toast. | str |
softsolidoutline
|
container default |
position |
Anchor point for this toast. | str |
top-righttop-lefttop-centerbottom-rightbottom-leftbottom-center
|
container default |
title |
Optional bold heading shown above the message. | str | — | |
duration |
Auto-dismiss time in milliseconds for this toast. Use 0 to keep it sticky. | int | — | container default |
class |
Extra Tailwind classes appended to this toast for one-off styling. | str | — |