Feedback
Toasts, confirmations, and dialogs.
Feedback tells the reader what just happened, or asks before something happens. A toast reports an outcome and goes away on its own. A confirmation and a dialog stop and wait for an answer.
import { button, confirm, defineDashboardPage, page, toast } from 'ohnejs/dashboard';
export default defineDashboardPage(() =>
page(
{ title: 'Guild' },
button('Disband the guild', {
variant: 'destructive',
onClick: async () => {
const yes = await confirm({
title: 'Disband the guild?',
action: 'Disband',
destructive: true,
});
if (yes) toast('The guild is disbanded', { type: 'success' });
},
}),
),
);Inside the frame, the toast stack and the dialog are already mounted. A page with frame: false wraps its content in base(...), which mounts them.
Toast
toast shows a short message at the top of the page:
toast('Raid roster saved', { type: 'success' })
toast({ key: 'dashboard.foundErrors', params: { count: 2 } }, { type: 'error' })typeisdefault,success,error,info, orwarning. Every type butdefaultleads with its icon.- The message takes a message key or plain text, and backticked values highlight.
- A toast stays 4 seconds. Hovering the stack pauses it.
useAction already toasts a failed write, so you add a toast only for success.
More in a toast
A toast can carry a second line, a button, and a close button:
toast('Baine was removed from the roster', {
description: 'He was the last warrior in group two.',
action: { label: 'Undo', onClick: () => restore('Baine') },
closeButton: true,
})- Clicking the
actiondismisses the toast after itsonClick. duration: Infinitykeeps a toast until it is dismissed.toastreturns an id. Pass it asidto update the showing toast in place, or todismissToast(id)to close it.queueToastwithshowAfterRouteChange: trueholds a toast until the next navigation, for a message that must survive one.
Confirm
confirm asks before an action and resolves true when the reader agrees:
const yes = await confirm({
title: 'Start `Icecrown Citadel`?',
body: 'Everyone in the group is summoned to the entrance.',
action: 'Start',
});- Cancel, Escape, and a click outside resolve
false. destructive: truepaints the agreeing button destructive, for what cannot be undone.- Ask a question in
title, and name the action inaction: "Disband", never "OK".
Dialog
openDialog is the general form, with buttons you name yourself. It resolves with the name of the one the reader clicked:
const side = await openDialog({
content: 'Which side does **Thrall** fight for?',
actions: [
{ name: 'alliance', label: 'Alliance' },
{ name: 'horde', label: 'Horde', variant: 'primary' },
],
});sideis typed'alliance' | 'horde' | undefined. Escape and a click outside resolveundefined.- The content is markdown-lite, like
**bold**, backticks, and links.markdown: falseshows plain text. - An action's
varianttakes the button variants,outlineby default. - One dialog shows at a time. Opening another replaces it, and the first promise never settles.