Potato logoACE
Skip to main contentGitLab logo

Toast

A Toast is a component that is used to convey an important message to the user for a short period of time. Toasts do not require user input and disappear after a set period of time. For messages that require user input use the ACE Modal component instead.

Note that when using multiple Toasts they occupy the same fixed position at the bottom of the viewport window. Developers should therefore add a way of dealing with multiple Toasts appearing at the same time if this is a possibility. An example of how this can be achieved using JavaScript is shown in the examples section below.

Toast conforms to the W3C WAI-ARIA authoring practices.

Setup

First import the styles into your main SASS file, replacing <path-to-node_modules> with the path to the node_modules directory relative to the file:

@import '<path-to-node_modules>/@potato/ace/components/toast/toast';

Alternatively ace.scss includes all ACE component SASS files, so if using multiple ACE components it can be imported instead:

@import '<path-to-node_modules>/@potato/ace/ace';

A CSS file is also provided for convenience and is located at <path-to-node_modules>/@potato/ace/components/toast/ace-toast.css.

Then import the class into your JavaScript entry point:

import '<path-to-node_modules>/@potato/ace/components/toast/toast';

For convenience the ES6 class is exported as Toast and the attribute names used by the class are exported as properties of ATTRS.

After the event DOMContentLoaded is fired on document an instance of Toast is instantiated within each <ace-toast> element and an ID ace-toast-<n> is added for any instance without one, where <n> is a unique integer. If the instance of Toast doesn't have a child with attribute ace-toast-inner, a child div is created, given this attribute and all other children of the Toast instance are moved into it. Once instantiation is complete a custom event ace-toast-ready is dispatched to window. See the Custom events section below for more details.

Usage

Toasts have an attribute ace-toast-visible which is initially set to false. This is an observed attribute and therefore dynamically be set to true which will cause the Toast to appear for a default time of 4 seconds before disappearing. Developers can specify a custom show-time by setting attribute ace-toast-show-time to the value of the show-time in milliseconds as demonstrated in the example below.

Styles

The following SASS is applied to Toast. The SASS variables use !default so can also be easily overridden by developers. SASS variables used that are not defined here are defined in <path-to-node_modules>/@potato/ace/common/constants.scss.

@import '../../common/constants';


// VARIABLES
$ace-toast-bg-color: #000 !default;
$ace-toast-border-radius: 8px !default;
$ace-toast-breakpoint: 600px !default;
$ace-toast-distance-from-bottom: 32px !default;
$ace-toast-font-size: 16px !default;
$ace-toast-max-width: 500px !default;
$ace-toast-mobile-max-width: 300px !default;
$ace-toast-padding: 16px !default;
$ace-toast-text-color: #fff !default;


// STYLES
ace-toast {
	background: $ace-toast-bg-color;
	border-radius: $ace-toast-border-radius;
	bottom: $ace-toast-distance-from-bottom;
	color: $ace-toast-text-color;
	font-size: $ace-toast-font-size;
	left: 50%;
	max-width: $ace-toast-mobile-max-width;
	padding: $ace-toast-padding;
	position: fixed;
	transform: translateX(-50%);
	z-index: $ace-toast-z-index;

	&:not([ace-toast-visible]) {
		display: none;
	}

	@media (min-width: $ace-toast-breakpoint) {
		max-width: $ace-toast-max-width;
	}
}

Custom events

Toast uses the following custom events, the names of which are available in its exported EVENTS object, similar to ATTRS, so they may be imported into other modules.

Dispatched events

The following events are dispatched to window by Toast.

Ready

ace-toast-ready

This event is dispatched when Toast finishes initialising. The event name is available as EVENTS.OUT.READY and its detail property is composed as follows:

'detail': {
	'id': // ID of Toast [string]
}

Changed

ace-toast-visibility-changed

This event is dispatched when Toast visibility changes. The event name is available as EVENTS.OUT.VISIBILITY_CHANGED and its detail property is composed as follows:

'detail': {
	'id': // ID of Toast [string]
	'visible': // Whether Toast is visible or not [boolean]
}

Examples

Each example contains a live demo and the HTML code that produced it. The code shown may differ slightly to that rendered for the demo as some components may alter their HTML when they initialise.

Simple Toast and short show-time Toast

A Toast with a default 4 second show-time and one with a custom 2 second show-time. The JavaScript used by this example is shown below.

Toast with standard 4 second show-time Toast with developer-defined 2 second show-time
<button id="simple-toast-btn">Show Toast</button>
<button id="short-show-time-toast-btn">Show Toast with 2 second show-time</button>

<ace-toast>
	Toast with standard 4 second show-time
</ace-toast>

<ace-toast ace-toast-show-time="2000">
	Toast with developer-defined 2 second show-time
</ace-toast>
import { ATTRS } from '/ace/components/toast/toast.js';

document.addEventListener('DOMContentLoaded', () => {
	const toastEl = document.getElementById('ace-toast-1');
	const secondToastEl = document.getElementById('ace-toast-2');
	const showToastBtn = document.getElementById('simple-toast-btn');
	const showSecondToastBtn = document.getElementById('short-show-time-toast-btn');

	showToastBtn.addEventListener('click', () => toastEl.setAttribute(ATTRS.VISIBLE, ''));
	showSecondToastBtn.addEventListener('click', () => secondToastEl.setAttribute(ATTRS.VISIBLE, ''));
});

Multiple Toasts

This example demonstrates how JavaScript can be used to deal with multiple toasts appearing at the same time.

First Toast Second Toast Third Toast
<button id="show-1st-toast-btn">Show first Toast</button>
<button id="show-2nd-toast-btn">Show second Toast</button>
<button id="show-3rd-toast-btn">Show third Toast</button>
<ace-toast>
	First Toast
</ace-toast>
<ace-toast>
	Second Toast
</ace-toast>
<ace-toast>
	Third Toast
</ace-toast>
import { ATTRS } from '/ace/components/toast/toast.js';

document.addEventListener('DOMContentLoaded', () => {
	const firstToastId = 'ace-toast-3';
	const secondToastId = 'ace-toast-4';
	const thirdToastId = 'ace-toast-5';
	const firstToastEl = document.getElementById(firstToastId);
	const secondToastEl = document.getElementById(secondToastId);
	const thirdToastEl = document.getElementById(thirdToastId);

	const positionToast = (toastEl) => {
		const TOAST_GAP = 10;
		let offsetTopOfHighestToast;
		const visibleToasts = document.querySelectorAll(`[${ATTRS.VISIBLE}]`);

		visibleToasts.forEach((visibleToast, index) => {
			const visibleToastOffsetTop = visibleToast.offsetTop;

			if (index === 0) {
				offsetTopOfHighestToast = visibleToastOffsetTop;
				return;
			}

			if (visibleToastOffsetTop < offsetTopOfHighestToast) {
				offsetTopOfHighestToast = visibleToastOffsetTop;
			}
		});
		toastEl.style.bottom = visibleToasts.length ? `${window.innerHeight - offsetTopOfHighestToast + TOAST_GAP}px` : '';
	};

	window.addEventListener('click', (e) => {
		const targetId = e.target.id;
		let toastEl;
		toastEl = targetId === 'show-1st-toast-btn' ? firstToastEl : toastEl;
		toastEl = targetId === 'show-2nd-toast-btn' ? secondToastEl : toastEl;
		toastEl = targetId === 'show-3rd-toast-btn' ? thirdToastEl : toastEl;

		if (!toastEl) {
			return;
		}

		positionToast(toastEl);
		toastEl.setAttribute(ATTRS.VISIBLE, '');
	});
});