Heads up, toasts will stack automatically
@@ -52,18 +49,15 @@
Toast Bootstrap Visual Test
diff --git a/scss/_toasts.scss b/scss/_toasts.scss
index 6fcf8df229a7..431b7b5bc163 100644
--- a/scss/_toasts.scss
+++ b/scss/_toasts.scss
@@ -1,6 +1,7 @@
@use "config" as *;
@use "variables" as *;
@use "mixins/border-radius" as *;
+@use "mixins/transition" as *;
// scss-docs-start toast-variables
$toast-max-width: 350px !default;
@@ -38,8 +39,11 @@ $toast-header-border-color: $toast-border-color !default;
--toast-header-color: #{$toast-header-color};
--toast-header-bg: #{$toast-header-background-color};
--toast-header-border-color: #{$toast-header-border-color};
+ --toast-delay: 5s;
// scss-docs-end toast-css-vars
+ // Hidden by default
+ display: none;
width: var(--toast-max-width);
max-width: 100%;
font-size: var(--toast-font-size);
@@ -49,14 +53,49 @@ $toast-header-border-color: $toast-border-color !default;
background-clip: padding-box;
border: var(--toast-border-width) solid var(--toast-border-color);
box-shadow: var(--toast-box-shadow);
+ opacity: 0%;
+ transform: translateY(1rem);
@include border-radius(var(--toast-border-radius));
- &.showing {
- opacity: 0;
+ // Entry/exit transitions
+ @include transition(opacity .3s ease, transform .3s ease, display .3s allow-discrete);
+
+ // Visible state
+ &.show {
+ display: block;
+ opacity: 1;
+ transform: translateY(0);
+
+ // Entry animation starting point
+ @starting-style {
+ opacity: 0;
+ transform: translateY(1rem);
+ }
+
+ // Autohide via CSS animation (fires after --toast-delay)
+ animation: toast-autohide .3s ease var(--toast-delay) forwards;
}
- &:not(.show) {
+ // Pause autohide on hover or focus
+ &.show:hover,
+ &.show:focus-within {
+ animation-play-state: paused;
+ }
+
+ // Reduced motion: instant autohide (transition handled by mixin)
+ @media (prefers-reduced-motion: reduce) {
+ &.show {
+ animation-duration: .01ms;
+ }
+ }
+ }
+
+ // Autohide keyframes — fades out after the animation-delay
+ @keyframes toast-autohide {
+ to {
display: none;
+ opacity: 0;
+ transform: translateY(1rem);
}
}
@@ -69,6 +108,11 @@ $toast-header-border-color: $toast-border-color !default;
max-width: 100%;
pointer-events: none;
+ // Auto-hide container when no visible toasts
+ &:not(:has(.toast.show)) {
+ display: none;
+ }
+
> :not(:last-child) {
margin-bottom: var(--toast-spacing);
}
@@ -85,8 +129,7 @@ $toast-header-border-color: $toast-border-color !default;
@include border-top-radius(calc(var(--toast-border-radius) - var(--toast-border-width)));
.btn-close {
- margin-inline-start: var(--toast-padding-x);
- margin-inline-end: calc(-.5 * var(--toast-padding-x));
+ margin-inline: var(--toast-padding-x) calc(-.5 * var(--toast-padding-x));
}
}
diff --git a/site/src/assets/partials/snippets.js b/site/src/assets/partials/snippets.js
index 0056131b7b1f..352e50f89a9e 100644
--- a/site/src/assets/partials/snippets.js
+++ b/site/src/assets/partials/snippets.js
@@ -47,25 +47,22 @@ export default () => {
})
}
- // Instantiate all toasts in docs pages only
+ // Show all toasts in docs examples (with autohide disabled)
document.querySelectorAll('.bd-example .toast')
.forEach(toastNode => {
- const toast = new bootstrap.Toast(toastNode, {
- autohide: false
- })
-
- toast.show()
+ toastNode.style.setProperty('--bs-toast-delay', '99999s')
+ bootstrap.Toast.getOrCreateInstance(toastNode).show()
})
- // Instantiate all toasts in docs pages only
+ // Live toast demo
// js-docs-start live-toast
const toastTrigger = document.getElementById('liveToastBtn')
const toastLiveExample = document.getElementById('liveToast')
if (toastTrigger) {
- const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
+ const toastInstance = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
toastTrigger.addEventListener('click', () => {
- toastBootstrap.show()
+ toastInstance.show()
})
}
// js-docs-end live-toast
diff --git a/site/src/content/docs/components/toasts.mdx b/site/src/content/docs/components/toasts.mdx
index 0330eb2073c4..10aa55e0612b 100644
--- a/site/src/content/docs/components/toasts.mdx
+++ b/site/src/content/docs/components/toasts.mdx
@@ -8,10 +8,13 @@ Toasts are lightweight notifications designed to mimic the push notifications th
## Overview
-Things to know when using the toast plugin:
+Things to know when using the toast component:
-- Toasts are opt-in for performance reasons, so **you must initialize them yourself**.
-- Toasts will automatically hide if you do not specify `autohide: false`.
+- Toasts use a lightweight `Toast` class that extends `BaseComponent` — show and hide via `Toast.getOrCreateInstance(el).show()` / `.hide()`.
+- Autohide is **CSS-driven** via animation — toasts hide after `5s` by default. Customize with the `--bs-toast-delay` CSS custom property.
+- Dismiss buttons with `data-bs-dismiss="toast"` work automatically via a delegated click handler.
+- Toasts fire custom events (`show.bs.toast`, `shown.bs.toast`, `hide.bs.toast`, `hidden.bs.toast`) that can be prevented.
+- Toasts pause their autohide timer on hover and focus-within.
@@ -35,10 +38,6 @@ Toasts are as flexible as you need and have very little required markup. At a mi
`} />
-
-Previously, our scripts dynamically added the `.hide` class to completely hide a toast (with `display:none`, rather than just with `opacity:0`). This is now not necessary anymore. However, for backwards compatibility, our script will continue to toggle the class (even though there is no practical need for it) until the next major version.
-
-
### Live example
Click the button below to show a toast (positioned with our utilities in the lower right corner) that has been hidden by default.
@@ -81,7 +80,17 @@ Click the button below to show a toast (positioned with our utilities in the low
We use the following JavaScript to trigger our live toast demo:
-
+```js
+const toastTrigger = document.getElementById('liveToastBtn')
+const toastLiveExample = document.getElementById('liveToast')
+
+if (toastTrigger) {
+ const toastInstance = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
+ toastTrigger.addEventListener('click', () => {
+ toastInstance.show()
+ })
+}
+```
### Translucent
@@ -167,6 +176,166 @@ Building on the above example, you can create different toast color schemes with
`} />
+### Status toasts
+
+Combine [color utilities]([[docsref:/utilities/colors]]) with inline SVG icons for clear success, error, and warning feedback. Use `text-bg-*` with `border-0` for bold, full-color toasts.
+
+
+
+
+
+
+ Changes saved.
+
+
+
+
+
+
+
+
+
+ Could not complete the request.
+
+
+
+
+
+
+
+
+
+ Your session expires in 5 minutes.
+
+
+
+
+
`} />
+
+### With icon badges
+
+For a subtler look, pair a neutral toast background with small colored icon circles. The badge draws the eye to the status without overwhelming the message.
+
+
+
+
+
+
+
+
Profile updated.
+
+
+
+
+
+
+
+
+
+
Upload failed. Please try again.
+
+
+
+
+
+
+
+
+
+
Storage almost full.
+
+
+
+
`} />
+
+### Undo action
+
+Include an undo link next to the dismiss button so users can reverse recent actions.
+
+
+
+ `} />
+
+### Call to action
+
+Pair an icon badge with a heading, description, and action buttons for prompts that need user interaction.
+
+
+
+
+
+
+
+ New version available
+
+ v6.0.1 includes performance improvements and bug fixes.
+
+
+
+
+
+ `} />
+
+### With illustration
+
+Use a placeholder image alongside a call-to-action for onboarding or promotional toasts.
+
+
+
+
+
+ Complete your profile
+ Add a photo and bio so teammates can recognize you.
+
+
+
+
+
+
+ `} />
+
+### With progress bar
+
+Show task progress inside a toast using Bootstrap's [progress component]([[docsref:/components/progress]]).
+
+
+
+ Importing data...
+ Step 3 of 4
+
+
+
+
+ customers-2024.csv
+ 75%
+
+
+
+
+
+ `} />
+
## Placement
Place toasts with custom CSS as you need them. The top right is often used for notifications, as is the top middle. If you’re only ever going to show one toast at a time, put the positioning styles right on the `.toast`.
@@ -266,17 +435,17 @@ Note that the live region needs to be present in the markup *before* the toast i
You also need to adapt the `role` and `aria-live` level depending on the content. If it’s an important message like an error, use `role="alert" aria-live="assertive"`, otherwise use `role="status" aria-live="polite"` attributes.
-As the content you’re displaying changes, be sure to update the [`delay` timeout](#options) so that users have enough time to read the toast.
+As the content you're displaying changes, be sure to update the [`--bs-toast-delay`](#variables) value so that users have enough time to read the toast.
```html
-
+
...
```
-When using `autohide: false`, you must add a close button to allow users to dismiss the toast.
+When disabling autohide, you must add a close button to allow users to dismiss the toast.
-
+
Bootstrap
@@ -288,7 +457,7 @@ When using `autohide: false`, you must add a close button to allow users to dism
`} />
-While technically it’s possible to add focusable/actionable controls (such as additional buttons or links) in your toast, you should avoid doing this for autohiding toasts. Even if you give the toast a long [`delay` timeout](#options), keyboard and assistive technology users may find it difficult to reach the toast in time to take action (since toasts don’t receive focus when they are displayed). If you absolutely must have further controls, we recommend using a toast with `autohide: false`.
+While technically it's possible to add focusable/actionable controls (such as additional buttons or links) in your toast, you should avoid doing this for autohiding toasts. Even if you give the toast a long `--bs-toast-delay`, keyboard and assistive technology users may find it difficult to reach the toast in time to take action (since toasts don't receive focus when they are displayed). If you absolutely must have further controls, we recommend using a toast with a very long `--bs-toast-delay`.
## CSS
@@ -304,58 +473,66 @@ While technically it’s possible to add focusable/actionable controls (such as
## Usage
-Initialize toasts via JavaScript:
+Show and hide toasts via the `Toast` class, which provides instance methods and custom events.
+
+### Show and hide
```js
-const toastElList = document.querySelectorAll('.toast')
-const toastList = [...toastElList].map(toastEl => new bootstrap.Toast(toastEl, option))
+const myToastEl = document.getElementById('myToast')
+const toast = bootstrap.Toast.getOrCreateInstance(myToastEl)
+
+// Show a toast
+toast.show()
+
+// Hide a toast
+toast.hide()
```
-### Triggers
+### Autohide delay
-
+Toasts automatically hide after `5s` by default. Customize the delay with the `--bs-toast-delay` CSS custom property:
-### Options
+```html
+
+
...
-
+
+
...
+```
-
-| Name | Type | Default | Description |
-| --- | --- | --- | --- |
-| `animation` | boolean | `true` | Apply a CSS fade transition to the toast. |
-| `autohide` | boolean | `true` | Automatically hide the toast after the delay. |
-| `delay` | number | `5000` | Delay in milliseconds before hiding the toast. |
-
+You can also set the delay programmatically:
-### Methods
+```js
+document.getElementById('myToast').style.setProperty('--bs-toast-delay', '10s')
+```
-
+### Dismiss
-
-| Method | Description |
-| --- | --- |
-| `dispose` | Hides an element’s toast. Your toast will remain on the DOM but won’t show anymore. |
-| `getInstance` | *Static* method which allows you to get the toast instance associated with a DOM element. For example: `const myToastEl = document.getElementById('myToastEl')` `const myToast = bootstrap.Toast.getInstance(myToastEl)` Returns a Bootstrap toast instance. |
-| `getOrCreateInstance` | *Static* method which allows you to get the toast instance associated with a DOM element, or create a new one, in case it wasn’t initialized. `const myToastEl = document.getElementById('myToastEl')` `const myToast = bootstrap.Toast.getOrCreateInstance(myToastEl)` Returns a Bootstrap toast instance. |
-| `hide` | Hides an element’s toast. **Returns to the caller before the toast has actually been hidden** (i.e. before the `hidden.bs.toast` event occurs). You have to manually call this method if you made `autohide` to `false`. |
-| `isShown` | Returns a boolean according to toast’s visibility state. |
-| `show` | Reveals an element’s toast. **Returns to the caller before the toast has actually been shown** (i.e. before the `shown.bs.toast` event occurs). You have to manually call this method, instead your toast won’t show. |
-
+Dismissal is handled automatically via a delegated click handler. Add `data-bs-dismiss="toast"` to a button **within the toast**:
+
+```html
+
+```
+
+### Pause on interaction
+
+Toasts pause their autohide countdown when hovered or when they contain a focused element (`:focus-within`). This is handled entirely via CSS `animation-play-state`.
### Events
| Event | Description |
| --- | --- |
-| `hide.bs.toast` | This event is fired immediately when the `hide` instance method has been called. |
-| `hidden.bs.toast` | This event is fired when the toast has finished being hidden from the user. |
-| `show.bs.toast` | This event fires immediately when the `show` instance method is called. |
-| `shown.bs.toast` | This event is fired when the toast has been made visible to the user. |
+| `show.bs.toast` | Fires immediately when the `show` instance method is called. |
+| `shown.bs.toast` | Fired when the toast has been made visible. |
+| `hide.bs.toast` | Fires immediately when the `hide` instance method is called. |
+| `hidden.bs.toast` | Fired when the toast has been hidden. |
```js
const myToastEl = document.getElementById('myToast')
+
myToastEl.addEventListener('hidden.bs.toast', () => {
- // do something...
+ // do something when the toast is hidden
})
```