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

Single line snackbar with action and icon
<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. Past two lines it is truncated, so keep the text short enough to fit.

Your photo was moved to the archive. You can restore it from the archive folder at any time within the next 30 days.
<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 without script. Use this first. Every overlay in the library takes the same pair, and it works before the page has hydrated. With timeout=0 the snackbar stays open until something closes it.

Manual controlled snackbar
<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" />

When there is no trigger to point at the snackbar, call show() and close() on the component, as shown under Methods. bind:open reports whether the snackbar is showing, also after it times out.

Bound to state
open: false
<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 has role="status", a polite live region. A screen reader finishes what it is saying and then reads 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 pauses while the snackbar is hovered or has focus, and starts over when both end. This keeps the action reachable with a keyboard. For a snackbar that must not close on its own, set timeout=0.

Theming

Tokens

TokenDefault value
--np-snackbar-container-color--np-color-inverse-surface
--np-snackbar-container-shape0.25rem
--np-snackbar-text-color--np-color-inverse-on-surface
--np-snackbar-action-color--np-color-inverse-primary

Example

Themed 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="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

AttributeTypeDefaultDescription
labelstringText to display in the snackbar
supportingTextstring | undefinedundefinedSupporting text to display in the snackbar
actionLabelstring | undefinedundefinedText of the action button. If undefined, there is no action button.
iconSnippet | undefinedundefinedIcon of the close button
iconAriaLabelstring'Close'Accessible label of the icon button.
timeoutnumber4000Time in milliseconds before the snackbar closes. With <= 0, the snackbar stays open until something closes it.
popover'auto' | 'manual''manual'With manual the snackbar closes on its timeout or when you hide it. With auto, a click elsewhere or Escape also closes it, but so does opening another popover.
onactionclick(event: Event) => void | undefinedundefinedCalled when the action button is clicked.
oniconclick(event: Event) => voidclose()Called when the icon button is clicked.
...attributesHTMLAttributes<HTMLDivElement>Passed to the container element.

Bindables

AttributeTypeDescription
openbooleanWhether the snackbar is shown. Defaults to false. Set it to true to show the snackbar and false to hide it. It updates when the snackbar opens or closes on its own.
elementHTMLElementThe root DOM element of the component, bound with bind:this.

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()}
/>
MethodTypeDescription
show() => voidShows the snackbar. Does nothing if it is already showing.
close() => voidHides the snackbar.