Skip to content

8. Toasts

A success toast when a note is created, updated, or deleted. We’ve had <kit-toast-region> and notificationModule() installed since chapter 1 — now we use them.

Approach 1: emit toasts from the persistence module

Section titled “Approach 1: emit toasts from the persistence module”

You could wire toasts into the persistence module’s command handlers. That’s tempting, but it conflates concerns: persistence shouldn’t know about UI feedback.

Approach 2: a dedicated toast-on-events module

Section titled “Approach 2: a dedicated toast-on-events module”

Better: a small module that observes note events and dispatches notification.show commands.

src/note-toasts-module.ts:

import { defineKitModule, type KitRuntime } from '@atheory-ai/kitsune-core'
export function noteToastsModule() {
const handle = (runtime: KitRuntime, message: string) =>
runtime.command({
type: 'notification.show',
payload: { message, tone: 'success' },
})
return defineKitModule({
name: 'note-toasts',
setup(runtime) {
runtime.on('note.created', () => handle(runtime, 'Note created'))
runtime.on('note.updated', () => handle(runtime, 'Note updated'))
runtime.on('note.deleted', (event) => {
const note = (event.payload?.note as { title?: string } | undefined)
const title = note?.title ?? 'Note'
handle(runtime, `${title} deleted`)
})
},
})
}

Install it in main.ts:

import { noteToastsModule } from './note-toasts-module.js'
shell.modules = [
notesModule(seedNotes),
auditModule(),
noteToastsModule(),
notificationModule(),
dialogModule(),
debugModule(),
]

Three lines (per event) added one capability. Nothing else moved. The persistence module didn’t change. The form didn’t change. The dialog didn’t change. We added an observer that maps domain events to UI feedback.

If you decided you wanted more feedback — say, a sound on delete — that’s another module observing the same events. If you decided you wanted less — silent updates — remove the module. The shape of the architecture rewards small, additive modules.

  • Create a note → green “Note created” toast.
  • Open and edit a note (we haven’t built edit yet, but if you did) → “Note updated”.
  • Delete a note → “$title deleted”.

<kit-toast-region> is a fixed-position container. Style it via custom properties:

kit-toast-region {
--kit-space-4: 1.5rem;
}

Or place it elsewhere by overriding inset-block-end and inset-inline-end on the host:

kit-toast-region {
inset-block-end: auto;
inset-block-start: 1rem;
inset-inline: 0;
margin-inline: auto;
}

It’s a regular custom element — CSS works.

The toast region has role="region" aria-live="polite" internally. Screen readers announce new toasts without moving focus. Errors should use tone="error" so the toast renders with role="alert" and is announced more aggressively.

Quill now reacts to writes with toasts. The new module touched zero existing files.

You’re starting to feel the architectural payoff: capabilities accumulate by adding files, not by editing existing ones. Most production frontend codebases are the opposite — every new feature touches every existing component.

A command palette. We’ll use the native popover API and a small input filter. Selecting a command dispatches it through the runtime. Same pattern as the rest of the app, with a different UI.

Next: Chapter 9 — Command Palette →