Snackbar
The snackbar uses the Popover API internally.
Usage
Show one snackbar at a time, never stacked. To update the message, change the text of the open snackbar instead of opening a second one.
Single-line snackbar
<script lang="ts">
import { Button, Snackbar } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
{#snippet icon()}
<Icon>close</Icon>
{/snippet}
<Button command="toggle-popover" commandfor="single-line-snackbar">Show snackbar</Button>
<Snackbar
{icon}
id="single-line-snackbar"
label="Single line snackbar with action and icon"
actionLabel="Action"
/>
Two-line snackbar
A long label wraps onto a second line instead of being cut off, so the whole message stays
readable. Past two lines it is truncated, so keep the text short enough to fit.
<script lang="ts">
import { Button, Snackbar } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
{#snippet icon()}
<Icon>close</Icon>
{/snippet}
<Button command="toggle-popover" commandfor="two-line-snackbar-demo">Show snackbar</Button>
<Snackbar
{icon}
id="two-line-snackbar-demo"
label="Your photo was moved to the archive. You can restore it from the archive folder at any time within the next 30 days."
actionLabel="Undo"
/>
Manual control
A snackbar is a popover, so command and commandfor on a trigger open and
close it with no script at all. Reach for this first: it is the same pair every overlay in the
library takes, and it works before the page has hydrated. With timeout=0 it stays open
until something closes it.
<script lang="ts">
import { Button, Snackbar } from 'noph-ui'
</script>
<Button command="show-popover" commandfor="manual-snackbar">Show snackbar</Button>
<Button command="hide-popover" commandfor="manual-snackbar">Hide snackbar</Button>
<Snackbar id="manual-snackbar" timeout={0} popover="manual" label="Manual controlled snackbar" />
Where there is no trigger to point at the snackbar, call show() and close() on the component, as under Methods. bind:open reports whether the snackbar is showing and follows it when it times out on its
own, so it is there to read rather than to drive.
<script lang="ts">
import { Button, Snackbar } from 'noph-ui'
let open = $state(false)
let snackbar: ReturnType<typeof Snackbar> | undefined = $state()
</script>
<Button onclick={() => snackbar?.show()}>Show snackbar</Button>
<Snackbar bind:this={snackbar} bind:open label="Bound to state" />
<span>open: {open}</span>
Accessibility
The snackbar is role="status", a polite live region, as the M3 spec asks for on the
web. A screen reader waits until it is done speaking and then reads the whole thing: the label, the supportingText and the action label together. The region is
named by its label and never takes focus. Pass aria-label to give it a
different name, and iconAriaLabel to translate the close button.
The timeout waits while the snackbar is hovered or holds focus and starts over once
it is left alone, so an action stays reachable with a keyboard. Give a snackbar that must not
vanish timeout=0.
Theming
Tokens
| Token | Default value |
|---|---|
--np-snackbar-container-color | --np-color-inverse-surface |
--np-snackbar-container-shape | 0.25rem |
--np-snackbar-text-color | --np-color-inverse-on-surface |
--np-snackbar-action-color | --np-color-inverse-primary |
Example
<script lang="ts">
import { Button, Snackbar } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
{#snippet icon()}
<Icon>close</Icon>
{/snippet}
<Button command="toggle-popover" commandfor="themed-snackbar">Show snackbar</Button>
<Snackbar
id="themed-snackbar"
{icon}
actionLabel="Action"
--np-snackbar-container-color="var(--np-color-tertiary)"
--np-snackbar-action-color="var(--np-color-on-tertiary)"
--np-snackbar-container-shape="1rem"
--np-snackbar-text-color="var(--np-color-on-tertiary)"
label="Themed snackbar"
/>
API
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
label | string | Text to display in the snackbar | |
supportingText | string | undefined | undefined | Supporting text to display in the snackbar |
actionLabel | string | undefined | undefined | Text to display in the action button. If undefined, the action button will not
be shown. |
icon | Snippet | undefined | undefined | Icon for the close affordance |
iconAriaLabel | string | 'Close' | Accessible label of the icon button. |
timeout | number | 4000 | Time in milliseconds before the snackbar closes. If set to <= 0, the
snackbar will stay open until another action triggers it. |
popover | 'auto' | 'manual' | 'manual' | With manual the snackbar closes on its timeout or when you hide
it. Use auto to also let a click elsewhere or Escape dismiss it, at the
cost of other popovers closing it. |
onactionclick | (event: Event) => void | undefined | undefined | Function that is triggered when clicking on the action button. |
oniconclick | (event: Event) => void | close() | Function that is triggered when clicking on the icon button. |
...attributes | HTMLAttributes<HTMLDivElement> | Attributes are passed to the component container. |
Bindables
| Attribute | Type | Description |
|---|---|---|
open | boolean | Whether the snackbar is shown. Defaults to false. Set it to true to show the snackbar and false to hide it; the snackbar writes
back when it opens or closes on its own. |
element | HTMLElement | A reference to the root DOM element of the component. This variable is bound using bind:this, allowing direct access to the underlying HTML element for manipulation or querying within
the component's logic. |
Methods
Bind a reference to the component with bind:this and type it with ReturnType<typeof Snackbar>; it is undefined until the component
has mounted, so call through ?..
<script lang="ts">
let snackbar: ReturnType<typeof Snackbar> | undefined = $state()
</script>
<Button onclick={() => snackbar?.show()}>Show snackbar</Button>
<Snackbar
bind:this={snackbar}
label="Reservation saved"
actionLabel="Undo"
onactionclick={() => snackbar?.close()}
/>| Method | Type | Description |
|---|---|---|
show | () => void | Shows the snackbar. A no-op if it is already showing. |
close | () => void | Hides the snackbar. |