---
area: "Learn"
parent: "Live fragments chapter"
url: "https://unpoly.com/learn/flashes"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [Live fragments chapter](https://unpoly.com/learn/live-fragments.md)</nav>

# Notification flashes

Unpoly can show confirmations, errors or warnings from your server responses in a notification area. An [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element in your layout is updated with every response and keeps its messages until new ones arrive.

<figure>
<img src="https://unpoly.com/images/api/flashes.png" alt="Screenshot of three flash messages">
<figcaption>

Three flash messages stacked on top of each other: a confirmation ("User created successfully!"), an error ("Could not save your changes!") and a warning ("Your credit card is expiring in 3 days."). Each kind has its own color, so the user can tell them apart at a glance.

</figcaption>
</figure>

<nav aria-label="Contents">

#### Contents

- [Placing flashes into the layout](#placement)
- [Rendering flash messages](#rendering-flash-messages)
- [Clearing flashes](#clearing-flashes)
- [Flashes in overlays](#overlays)
- [Caching considerations](#caching)
- [Building a custom flashes container](#building-a-custom-flashes-container)

</nav>

## Placing flashes into the layout {#placement}

In your application layout, place an empty element with an [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) attribute. This indicates where future flash messages should be inserted.

A popular place for flashes is outside your [main fragment](https://unpoly.com/api/main.md):

```html
<nav>
  Navigation items ...
</nav>
<div up-flashes></div>
<main>
  Main page content ...
</main>
```

You may also place the container inside your main fragment. See [flashes in overlays](#overlays) for how that choice affects pages with overlays.

## Rendering flash messages {#rendering-flash-messages}

To render a flash message, include an [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element in your response. The element's content should be the messages you want to render:

```html
<div up-flashes>
  <strong>User was updated!</strong>
</div>

<main>
  Main response content ...
</main>
```

### Flashes are targeted automatically {#flashes-are-targeted-automatically}

The flashes are always updated, even if they aren't [targeted](https://unpoly.com/learn/targeting-fragments.md) directly. In the example above, rendering `main` would also update the [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element.

This works like a [hungry element](https://unpoly.com/learn/hungry-elements.md): the container piggy-backs on every render pass in its layer and in overlays above it. You don't need to name it in any `[up-target]` attribute.

This also works for [error responses](https://unpoly.com/learn/error-responses.md), so an error flash rendered with a form's validation errors is shown too.

## Clearing flashes {#clearing-flashes}

By default flash messages are [kept](https://unpoly.com/api/up-keep.md) until they are replaced by new messages.

An [empty](https://unpoly.com/api/up.element.isEmpty.md) [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element will **not** clear existing messages. Hence it is safe to always include an empty [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element in your application layout to indicate where future flashes should be placed.

### Removing messages after a delay {#clearing-after-delay}

Typically you want to clear flash messages after some time. This [compiler](https://unpoly.com/learn/enhancing-elements.md) removes child elements of your [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) container after 5 seconds:

```js
up.compiler('[up-flashes] > *', function(message) {
  setTimeout(() => up.destroy(message), 5000)
})
```

> #### Important
>
> We're only removing the contents of [`[up-flashes]`](https://unpoly.com/api/up-flashes.md), but not the container itself. The empty flashes container must remain in the layout to indicate where future flashes should be [placed](#placement).

To animate the removal, pass an [`{ animation }`](https://unpoly.com/api/up.destroy.md#options.animation) option to [`up.destroy()`](https://unpoly.com/api/up.destroy.md).

## Flashes in overlays {#overlays}

When you [open an overlay](https://unpoly.com/learn/opening-overlays.md), its content is rendered from a server response like any other fragment. Where flash messages from that response appear depends on where your [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) containers are.

### One container for all layers {#one-container-for-all-layers}

With the container [outside the main fragment](#placement), only the root layer has an [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element. Flashes from any overlay are rendered into that one container, on the root layer.

### One container per layer {#one-container-per-layer}

For styling reasons you may also wish to place the [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) container inside your [main fragment](https://unpoly.com/api/main.md):

```html
<nav>
  Navigation items ...
</nav>
<main>
  <div up-flashes></div>

  Main page content ...
</main>
```

Each overlay that renders a main fragment then brings its own [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) container. Flash messages from overlay content are rendered into the overlay's own container. Only when the overlay is closing, its [flashes are rendered into the parent layer](#from-closing-overlays) instead of being discarded.

### Flashes from closing overlays are shown on a parent layer {#from-closing-overlays}

Sometimes a fragment update will cause an overlay to [close](https://unpoly.com/learn/closing-overlays.md), e.g. when a [close condition](https://unpoly.com/learn/subinteractions.md#close-conditions) is reached. In that case no new elements will be rendered into the closing overlay. Any confirmation flashes from the final overlay interaction would be lost.

The [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) element addresses this by picking up flashes from a closing overlay and rendering them into the parent layer.

## Caching considerations {#caching}

Responses with notification flashes don't [cache](https://unpoly.com/learn/caching.md) well. When such a response is re-used, old flash messages will be shown again.

There are several workarounds for this:

1. Do not cache responses with flashes.
2. Have a [compiler suppress flash messages](#suppressing-cached-flashes) that have been shown before.
3. Use a different URL for responses with flashes, such as `/users/3?updated=true`.
4. Transport flash messages in a client-readable cookie instead.

### Suppressing cached flashes {#suppressing-cached-flashes}

You can write a [compiler](https://unpoly.com/learn/enhancing-elements.md) that removes the DOM elements for flashes that have already been shown. This allows you to keep caching responses with flashes, but only show each message once.

To give each flash message an identity that we can track, render it with a random attribute, such as `[data-nonce]`:

```html
<div up-flashes>
  <strong data-nonce="6792525983">User was updated!</strong>
</div>
```

The client can now track which nonces it has already seen. When a cached response is re-used, it recognizes an older nonce and removes the message element:

```js
let seen = new Set()

up.compiler('[up-flashes] > *', function(message, { nonce }) {
  if (seen.has(nonce)) {
    // Remove a flash message that has already been shown
    message.remove()
  } else {
    // Remember that we've seen this flash message
    seen.add(nonce)

    // Only track the last 100 nonces
    if (seen.size > 100) {
      seen.delete(seen.values().next().value)
    }
  }
})
```

Because compilers run before the browser paints, removed flash messages will never be visible to the user.

## Building a custom flashes container {#building-a-custom-flashes-container}

If you cannot work with the behavior of [`[up-flashes]`](https://unpoly.com/api/up-flashes.md), consider building your own custom flashes container.

You can use the implementation of [`[up-flashes]`](https://unpoly.com/api/up-flashes.md) as a template, which looks like this:

```html
<div
  id="flashes"
  role="alert"
  up-hungry
  up-if-layer="subtree"
  up-keep
  up-on-keep="if (!up.element.isEmpty(event.newFragment)) event.preventDefault()"
>
</div>
```

The [`[up-hungry]`](https://unpoly.com/api/up-hungry.md) attribute makes the container update with every render pass. Its [`[up-if-layer="subtree"]`](https://unpoly.com/api/up-hungry.md#up-if-layer) setting also catches updates from overlays, which is how [flashes from a closing overlay](#from-closing-overlays) reach the parent layer. The [`[up-keep]`](https://unpoly.com/api/up-keep.md) attribute keeps existing messages, but the [`[up-on-keep]`](https://unpoly.com/api/up-keep.md#up-on-keep) callback lets a non-empty container replace them.

<nav aria-label="Reading order">

- [Previous: Hungry elements](https://unpoly.com/learn/hungry-elements.md)
- [Next: History](https://unpoly.com/learn/history.md)

</nav>

