# Snackbar

> Material Design 3 snackbars, from the HTML.

## Introduction

Snackbars show short updates about app processes at the bottom of the screen. They should not interrupt browsing — people can keep using the page without interacting with the bar. A `.snackbar` is the bar. A `<p>` is the supporting text. A trailing `<button>` is the optional action; a `.circle` button is the optional close.

Tokens follow the [M3 snackbar spec](https://m3.material.io/components/snackbar/specs). The container is `inverse-surface`, 4dp corners, elevation 3, 48dp minimum. Supporting text is `body-medium` / `inverse-on-surface`, two lines max. The action is a `label-large` / `inverse-primary` text button. Close is a 24dp `inverse-on-surface` icon. On compact viewports the bar is inset 8dp from the edges; from the Medium breakpoint up it hugs content (344–672dp) and sits centered 24dp from the bottom.

A snackbar can time out on its own (4 seconds, or 10 with an action) or stay until the user acts (`displayLength: Infinity`). Only one shows at a time. Snackbar is not in `AutoInit()` — construct one when you need it, or drop a static `.snackbar` in the page and add `.active` to pin it.

Show Show with action Show with close

Photo saved to album

Item archived

Undo

Can't send photo. Retry in 5 seconds.

Retry

```
new Expressive.Snackbar({ text: 'Photo saved to album' });

new Expressive.Snackbar({
  text: 'Item archived',
  action: 'Undo',
  onAction: function() { /* restore */ }
});

new Expressive.Snackbar({
  text: "Can't send photo. Retry in 5 seconds.",
  action: 'Retry',
  dismissible: true
});
```

The constructor wraps `text` in a `<p>` and appends the action and close when those options are set. The live region is `role="status"` with `aria-live="polite"`, so it announces without stealing focus.

## Initialization

The IIFE bundle exposes `Expressive.Snackbar`. Snackbar is not in `AutoInit()` — construct one when you need it.

```
new Expressive.Snackbar({
  text: 'I am a snackbar!'
});
```

One way to hook that up is a click handler on a button:

```
<button type="button" id="snackbar-basic">Show</button>
```

```
document.getElementById('snackbar-basic').addEventListener('click', function() {
  new Expressive.Snackbar({ text: 'I am a snackbar!' });
});
```

## Markup

The same anatomy works as static HTML. Without `.active` the bar is in-flow — useful for previews. With `.active` it pins to the bottom of the viewport, centered from the Medium breakpoint. Add `.top` only if you must move it off the bottom.

Show static snackbar

Single-line snackbar with action

Action

```
<div class="snackbar">
  <p>Photo saved to album</p>
</div>

<div class="snackbar">
  <p>Item archived</p>
  <button type="button">Undo</button>
</div>

<div class="snackbar active">
  <p>Single-line snackbar with action</p>
  <button type="button">Action</button>
</div>
```

`.active` does not dismiss itself. Add and remove the class, or use the constructor if you want the 4-second timer and swipe-to-dismiss.

## Options

You can customize each snackbar with these options.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `text` | String | `''` | Plain-text supporting text, wrapped in a `<p>`. If set, it replaces any HTML from `snackbarId`. |
| `action` | String | `''` | Optional action label. Rendered as a trailing text button. |
| `onAction` | Function | `null` | Called when the action button is pressed. The snackbar still dismisses. |
| `dismissible` | Boolean | `false` | Show a trailing close icon button. |
| `snackbarId` | String | — | Id of a `<template>` (or another element) used as the snackbar body. |
| `displayLength` | Number | `4000` | How long the snackbar stays before it dismisses, in milliseconds. Default 4s, or 10s when `action` is set. Pass `Infinity` to remain until the user takes action. |
| `inDuration` | Number | `300` | Enter transition duration, in milliseconds. |
| `outDuration` | Number | `375` | Exit transition duration, in milliseconds. |
| `classes` | String | `''` | Space-separated classes added to the snackbar. `rounded` is a stadium. `top` moves the bar off the bottom. |
| `completeCallback` | Function | `null` | Called when the snackbar is dismissed. |
| `activationPercent` | Number | `0.8` | Fraction of the snackbar’s width a drag must travel to dismiss it. |
| `root` | Element | `null` | Any element in the tree the snackbar should render into. Pass one when the page lives in a shadow root, so the container is appended there rather than to `document.body`. |

## Methods

> Instance methods are called on the snackbar. You can get the instance like this:

```
const instance = Expressive.Snackbar.getInstance(elem);
```

### .dismiss();

Dismiss this snackbar with its exit animation. Runs `completeCallback` when the animation finishes.

```
instance.dismiss();
```

### Snackbar.dismissAll();

Dismiss every snackbar that is currently showing.

```
Expressive.Snackbar.dismissAll();
```

## Properties

| Name | Type | Description |
| --- | --- | --- |
| `el` | Element | The snackbar element. |
| `options` | Object | The options the instance was initialized with. |
| `panning` | Boolean | Whether the snackbar is being dragged. |
| `timeRemaining` | Number | Milliseconds left before the snackbar dismisses. |

## Custom HTML

Pass `snackbarId` pointing at a `<template>`. The first child of the template is cloned as the snackbar. Leave `text` empty so the HTML is kept. Use the same anatomy as a static snackbar.

Show Snackbar 1 Show Snackbar 2

```
<button type="button" class="tonal" id="snackbar-html-1">Show Snackbar 1</button>
<template id="my-snackbar-1">
  <div>
    <p>This is snackbar nº1 with a <a href="https://github.com">link</a></p>
  </div>
</template>
```

```
new Expressive.Snackbar({ snackbarId: 'my-snackbar-1' });
```

## Callback

Run a function when the snackbar is dismissed.

Show Snackbar

```
new Expressive.Snackbar({
  text: 'I will call back when dismissed',
  completeCallback: function() {
    new Expressive.Snackbar({ text: 'Your snackbar was dismissed' });
  }
});
```

## Styling

Pass classes in the `classes` option. `rounded` is a 24dp stadium — the M3 default is 4dp. Snackbars sit at the bottom; `top` is the exception.

Show round Snackbar Show at top

```
new Expressive.Snackbar({
  text: 'I am a snackbar!',
  classes: 'rounded'
});

new Expressive.Snackbar({
  text: 'Posted from the top',
  classes: 'top'
});
```

## Dismiss a Snackbar Programmatically

To remove a specific snackbar, get the instance from the snackbar element and call `dismiss()`. Swipe also dismisses — drag past 80% of the width (or flick). The action and close buttons are not swipe handles.

Show Snackbar Dismiss a snackbar Dismiss all

```
const snackbarElement = document.querySelector('.snackbar');
const snackbarInstance = Expressive.Snackbar.getInstance(snackbarElement);
snackbarInstance.dismiss();
```

### Dismiss all snackbars

```
Expressive.Snackbar.dismissAll();
```
