Snackbar
Snackbars provide brief messages about app processes at the bottom of the screen.
Snackbars inform users of a process that an app has performed or will perform. They appear temporarily, towards the bottom of the screen. They shouldn't interrupt the user experience, and they don't require user input to disappear.
Introduction
The MD3 Expressive Snackbar is a lightweight notification component used for low-priority feedback. It provides a non-disruptive way to confirm actions (e.g., "Message sent") or inform about background processes. Built with a queuing system, it ensures that messages are delivered sequentially without overlapping.
Anatomy
- Container: A dark surface (
bg-m3-inverse-surface,text-m3-inverse-on-surface) with rounded corners (4dp) and Level 3 elevation shadow that floats at the bottom of the screen. - Message Text: A short string describing the event (
text-sm leading-5 font-normal). - Action (Optional): A single text button with MD3 interactive state layers for the user to respond to the notification (e.g., "Undo").
- Close Affordance (Optional): A standard icon button (
IconButtonwithcolorStyle="standard") to dismiss the snackbar immediately.
Variants
Basic Snackbar
A simple message that appears and automatically dismisses after a short duration.
With Action
Includes a text button for a follow-up action. The showSnackbar function returns a promise that resolves to 'action-performed' when the action is clicked.
With Dismiss Button
Includes a dedicated close (X) icon button to dismiss the notification on demand.
Multi-line / New Line Action
For longer messages or labels, the action can be placed on a new line (Column layout) to maintain readability.
Features
Queuing System
If multiple snackbars are triggered in rapid succession, the system automatically queues them, showing one at a time to avoid overwhelming the user.
Automatic Dismissal
Snackbars are temporary and dismiss themselves after a delay (default 4 000 ms for short, 7 000 ms for long, or custom millisecond duration).
State Layers & Motion
Action buttons and dismiss icon buttons feature MD3 Expressive state layers (hover, focus, pressed) and spring physics animations powered by Framer Motion.
Usage
Setup via MD3ThemeProvider
The recommended setup is enabling snackbars globally in your root layout via MD3ThemeProvider:
import { MD3ThemeProvider } from "@bug-on/m3-expressive";
export function Root({ children }: { children: React.ReactNode }) {
return (
<MD3ThemeProvider enableSnackbar>
{children}
</MD3ThemeProvider>
);
}
Alternative Setup via SnackbarProvider
For standalone apps or scoped sections without MD3ThemeProvider:
import { SnackbarProvider } from "@bug-on/m3-expressive";
export function App({ children }: { children: React.ReactNode }) {
return (
<SnackbarProvider>
{children}
</SnackbarProvider>
);
}
Triggering a Snackbar
Use the useSnackbar hook to access the showSnackbar function.
import { Button, useSnackbar } from "@bug-on/m3-expressive";
export function MyComponent() {
const { showSnackbar } = useSnackbar();
const handleSave = async () => {
const result = await showSnackbar({
message: "Profile updated",
actionLabel: "Undo",
duration: "short",
});
if (result === "action-performed") {
// Undo logic...
}
};
return <Button onClick={handleSave}>Save</Button>;
}
Best Practices
Do
- Keep messages short and direct.
- Use snackbars for non-critical confirmation messages.
- Provide an "Undo" action for destructive operations if possible.
- Ensure the snackbar doesn't obscure important UI elements like FABs or Navigation Bars.
Don't
- Don't use snackbars for critical errors that require immediate attention (use a Dialog instead).
- Don't put more than one action in a snackbar.
- Avoid using snackbars for long-lasting or permanent information.
Accessibility
- Roles: Uses
role="status"witharia-live="polite"andaria-atomic="true"to ensure screen readers announce the message without interrupting the current task. - Duration: Provides enough time for users to read the message. The
"long"(7 000 ms) duration is recommended for snackbars with actions. - Interaction: The action button and close affordance are reachable and focusable via keyboard.
- Reduced Motion: Respects
prefers-reduced-motionwith clean fade transitions instead of spatial slide/spring motion.
API Reference
useSnackbar
Hook providing access to the snackbar system from the nearest SnackbarProvider or MD3ThemeProvider.
const { showSnackbar } = useSnackbar();
| Property | Type | Description |
|---|---|---|
showSnackbar | (visuals: SnackbarVisuals) => Promise<SnackbarResult> | Triggers a snackbar and returns a promise resolving to 'action-performed' or 'dismissed'. |
useSnackbarState
Low-level hook that manages the snackbar queue and mutex state.
const { current, showSnackbar, _dismiss } = useSnackbarState();
| Return Property | Type | Description |
|---|---|---|
current | SnackbarData | null | Currently active snackbar data, or null when idle. |
showSnackbar | (visuals: SnackbarVisuals) => Promise<SnackbarResult> | Enqueues and displays a snackbar. |
_dismiss | (result: SnackbarResult) => void | Internal callback to dismiss the active snackbar. |
SnackbarVisuals
Visual configuration passed to showSnackbar().
| Prop | Type | Default | Description |
|---|---|---|---|
message | string | — | Required. Main notification message text. |
actionLabel | string | — | Label for the optional text action button. |
withDismissAction | boolean | false | When true, renders a close (X) icon button. |
actionOnNewLine | boolean | false | When true, renders the action button below the message (Column layout). |
duration | "short" | "long" | number | "short" | Auto-dismiss duration ("short" = 4 000 ms, "long" = 7 000 ms, or custom milliseconds). |
className | string | — | Additional CSS className applied to the snackbar container. |
SnackbarResult
Type representing the outcome of a snackbar instance.
type SnackbarResult = "action-performed" | "dismissed";
SnackbarHostProps
Props for the SnackbarHost component.
| Prop | Type | Default | Description |
|---|---|---|---|
state | UseSnackbarStateReturn | — | Required. State returned by useSnackbarState(). |
className | string | — | Additional CSS className applied to the fixed host container. |
Tokens & Exports
| Export | Type | Description |
|---|---|---|
SnackbarProvider | Component | Context provider that wires SnackbarHost and exposes useSnackbar. |
SnackbarHost | Component | AnimatePresence container that renders active snackbars sequentially. |
Snackbar | Component | Pure display component for a single snackbar instance. |
SnackbarContext | Context | React Context holding the { showSnackbar } function. |
useSnackbar | Hook | Consumer hook to trigger snackbars imperatively. |
useSnackbarState | Hook | Low-level queue and state management hook. |
SnackbarVisuals | Interface | Visual configuration options for a snackbar. |
SnackbarData | Interface | Runtime state data including id, visuals, and resolve callback. |
SnackbarResult | Type | Union type "action-performed" | "dismissed". |
SnackbarDuration | Type | Union type "short" | "long" | number. |