# Toast

Toast notification system with body-portaled Toaster, free-function toast() API, and a shared client stack (SSR-safe).

- Package: `@mielui/svelte`
- Component version: `3.1.0`
- Depends on Mielui components: _internal/utils, button, notch
- Shared utilities: components/_internal/inset-layout, components/_internal/button-attributes, components/_internal/surface, hugeicons-icon, utils.cn, transition, utils.createContext

## Install

~~~~sh
pnpm dlx @mielui/svelte add toast
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Action

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| action | ToastAction | - | Yes | No | Label and handler for the action. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Actions

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Close

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Content

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Footer

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Icon

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| toast | Toast | - | Yes | No | Toast data from the store. |
| surface | "solid" \| "glass" \| undefined | toast.surface | No | No | Surface treatment. Omit it to inherit `--mielui-surface` from the theme. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Title

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Toaster

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| variant | "default" \| "notch" \| undefined | 'default' | No | No | `notch` presents toasts as a Notch attached to an edge. |
| side | "top" \| "bottom" \| "left" \| "right" \| undefined | 'top' | No | No | Viewport edge toasts appear from. |
| labels | ToastLabels \| undefined | - | No | No | Overrides the built-in text and accessible names. Every key is optional and English is the fallback. |



### Public types

~~~~ts
import { getToastUIState, toast } from './lib.svelte';
import * as Toast from './parts';
import Toaster from './toaster.svelte';

export type {
    Toast as ToastType,
    ToastAction,
    ToastFn,
    ToastState,
    ToastUIState
} from './lib.svelte';
export { Action, Actions, Close, Content, Footer, Icon, Root, Title } from './parts';
export type ToastLabels = {
    /** Accessible name of the notifications region. */
    region?: string;
    /** Accessible name of a toast's dismiss button. */
    dismiss?: string;
    /** Accessible name of the notch button that shows the previous notification. */
    previous?: string;
    /** Accessible name of the notch button that shows the next notification. */
    next?: string;
    /** Accessible name of the notch position counter. `position` starts at 1. */
    position?: (position: number, total: number) => string;
    /** Visible notch position counter, such as 2 of 5. `index` starts at 1. */
    count?: (index: number, total: number) => string;
};

export { getToastUIState, Toast, Toaster, toast };
~~~~

## Examples

### Actions

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { toast } from '@mielui/svelte/components/toast';

    function notify() {
        toast({
            title: 'Changes ready',
            description:
                'Your theme is saved as a draft. Apply it to the workspace when you are ready.',
            persistent: true,
            actions: [
                {
                    label: 'Discard',
                    callback: () => {
                        toast.info('Draft discarded');
                    }
                },
                {
                    label: 'Apply',
                    variant: 'primary',
                    callback: () => {
                        toast.success('Theme applied');
                    }
                }
            ]
        });
    }
</script>

<Button onclick={notify}>Show action toast</Button>
~~~~

### All Types

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { toast } from '@mielui/svelte/components/toast';

    function showDefault() {
        toast({
            title: 'Heads up',
            description: 'A neutral toast.'
        });
    }

    function showSuccess() {
        toast.success('Profile updated', {
            description: 'Your changes have been saved.'
        });
    }

    function showError() {
        toast.error('Request failed', {
            description: 'Could not connect to the server.'
        });
    }

    function showWarning() {
        toast.warning('Storage almost full', {
            description: 'You have 200 MB remaining.'
        });
    }

    function showInfo() {
        toast.info('New version', {
            description: 'Refresh to update.'
        });
    }
</script>

<div class="flex flex-wrap gap-2">
    <Button onclick={showDefault}>Default</Button>
    <Button onclick={showSuccess}>Success</Button>
    <Button onclick={showError}>Error</Button>
    <Button onclick={showWarning}>Warning</Button>
    <Button onclick={showInfo}>Info</Button>
</div>
~~~~

### Composition

~~~~svelte
<script lang="ts">
    import { Toast } from '@mielui/svelte/components/toast';
</script>

<div class="w-full max-w-sm">
    <Toast.Root toast={{ title: 'Draft saved', type: 'success' }}>
        <Toast.Content class="gap-1">
            <div class="flex items-center gap-2">
                <Toast.Icon />
                <Toast.Title />
            </div>
            <span>Your theme is saved locally. You can keep editing before publishing.</span>
        </Toast.Content>
    </Toast.Root>
</div>
~~~~

### Glass

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { toast } from '@mielui/svelte/components/toast';

    function showDetails() {
        toast.info('Deployment details', {
            description: 'Preview build completed with no errors.'
        });
    }

    function deploy() {
        toast.success('Deployment ready', {
            surface: 'glass',
            description: 'The preview build completed successfully.',
            actions: [
                {
                    label: 'View details',
                    callback: showDetails
                }
            ]
        });
    }
</script>

<Button onclick={deploy}>Deploy</Button>
~~~~

### Hero

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { toast } from '@mielui/svelte/components/toast';

    function showDetails() {
        toast.info('Deployment details', {
            description: 'Preview build completed with no errors.'
        });
    }

    function deploy() {
        toast.success('Deployment ready', {
            description: 'The preview build completed successfully.',
            actions: [
                {
                    label: 'View details',
                    callback: showDetails
                }
            ]
        });
    }
</script>

<Button onclick={deploy}>Deploy</Button>
~~~~

### Notch

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { Toaster, toast } from '@mielui/svelte/components/toast';

    let count = 0;

    function notify() {
        count += 1;
        toast.success(`Export ${count} ready`, {
            description: 'Your workspace export is ready to download.',
            duration: 12000
        });
    }

    function activity() {
        toast.loading('Syncing workspace', {
            description: 'This activity stays until you dismiss it.'
        });
    }
</script>

<Toaster variant="notch" side="top" />
<div class="flex flex-wrap justify-center gap-2">
    <Button variant="secondary" onclick={notify}>Add notification</Button>
    <Button variant="secondary" onclick={activity}>Add ongoing activity</Button>
</div>
~~~~

### Promise

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { Switch } from '@mielui/svelte/components/switch';
    import { toast } from '@mielui/svelte/components/toast';
    import { onDestroy } from 'svelte';

    let fail = $state(false);
    let pending = $state(false);
    let timer: ReturnType<typeof setTimeout> | undefined;
    let notification: ReturnType<typeof toast.promise> | undefined;

    function save() {
        const shouldFail = fail;
        pending = true;

        const request = new Promise<string>((resolve, reject) => {
            timer = setTimeout(() => {
                pending = false;

                if (shouldFail) {
                    reject(new Error('The server could not save your changes.'));
                } else {
                    resolve('Profile');
                }
            }, 1600);
        });

        notification = toast.promise(request, {
            loading: 'Saving profile…',
            success: (name) => `${name} saved`,
            error: 'Could not save profile',
            errorDescription: 'Your changes are still here. Try again.'
        });
    }

    onDestroy(() => {
        clearTimeout(timer);
        notification?.exit?.();
    });
</script>

<div class="flex flex-wrap items-center gap-4">
    <Button onclick={save} disabled={pending}>Save profile</Button>
    <Switch bind:checked={fail} label="Simulate failure" />
</div>
~~~~

For the rendered reference, visit [/docs/components/toast](/docs/components/toast).
