A custom HTML element for displaying dismissible alerts and toast notifications
Set the variant
attribute to change the alert’s variant.
<alert-element open variant="info">
<strong>New feature available!</strong><br>
You can now schedule reports to be sent automatically to your inbox every week.
</alert-element>
<alert-element open variant="success">
<strong>Your profile has been updated</strong><br>
All changes have been saved and will take effect immediately.
</alert-element>
<alert-element open variant="neutral">
<strong>Scheduled maintenance</strong><br>
Our servers will be undergoing maintenance this Saturday from 2 AM to 4 AM UTC.
</alert-element>
<alert-element open variant="warning">
<strong>Password expires soon</strong><br>
Your current password will expire in 5 days. Please update it to avoid losing access.
</alert-element>
<alert-element open variant="danger">
<strong>Failed to connect to database</strong><br>
Please check your configuration settings and try again. Contact support if the issue persists.
</alert-element>
Use the icon
slot to display an icon next to the alert message.
<alert-element open variant="success">
<span slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" width="1.5em" height="1.5em" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
<path d="m10.97 4.97-.02.022-3.473 4.425-2.093-2.094a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05"/>
</svg>
</span>
<strong>Your profile has been updated!</strong><br>
All changes have been saved and will take effect immediately.
</alert-element>
Set the closable
attribute to display a close button that hides the alert when clicked.
<button type="button">Show Alert</button>
<alert-element variant="info" closable>
Click the close button to hide this alert.
</alert-element>
<script>
const button = document.querySelector('button');
const alert = document.querySelector('alert-element');
alert.addEventListener('alert-show', () => {
button.setAttribute('disabled', '');
});
alert.addEventListener('alert-after-hide', () => {
button.removeAttribute('disabled');
});
button.addEventListener('click', () => {
alert.show();
});
</script>
Use the close
slot to provide a custom close button.
<alert-element variant="info" open closable>
This is an alert with a custom close button.
<span slot="close">Close</span>
</alert-element>
Set the duration
attribute to automatically hide the alert after a specified period of time,
unless you interact with it while still open.
<button type="button">Show Alert</button>
<alert-element variant="info" closable duration="3000">
This alert will automatically hide itself after 3 seconds, unless you interact with it.
</alert-element>
<script>
const button = document.querySelector('button');
const alert = document.querySelector('alert-element');
button.addEventListener('click', () => {
alert.show();
});
</script>
You can create custom variants by using the variant
attribute with a custom value
and applying your own CSS styles.
<style>
alert-element {
--alert-custom-variant-color: #ec4899;
}
@media (prefers-color-scheme: dark) {
alert-element {
--alert-custom-variant-color: #fe94cd;
}
}
alert-element[variant="custom"]::part(base) {
border-top-color: var(--alert-custom-variant-color);
}
alert-element[variant="custom"]::part(icon) {
color: var(--alert-custom-variant-color);
}
</style>
<alert-element open variant="custom">
<span slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" width="1.5em" height="1.5em" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path fill-rule="evenodd" d="m4.736 1.968-.892 3.269-.014.058C2.113 5.568 1 6.006 1 6.5 1 7.328 4.134 8 8 8s7-.672 7-1.5c0-.494-1.113-.932-2.83-1.205l-.014-.058-.892-3.27c-.146-.533-.698-.849-1.239-.734C9.411 1.363 8.62 1.5 8 1.5s-1.411-.136-2.025-.267c-.541-.115-1.093.2-1.239.735m.015 3.867a.25.25 0 0 1 .274-.224c.9.092 1.91.143 2.975.143a30 30 0 0 0 2.975-.143.25.25 0 0 1 .05.498c-.918.093-1.944.145-3.025.145s-2.107-.052-3.025-.145a.25.25 0 0 1-.224-.274M3.5 10h2a.5.5 0 0 1 .5.5v1a1.5 1.5 0 0 1-3 0v-1a.5.5 0 0 1 .5-.5m-1.5.5q.001-.264.085-.5H2a.5.5 0 0 1 0-1h3.5a1.5 1.5 0 0 1 1.488 1.312 3.5 3.5 0 0 1 2.024 0A1.5 1.5 0 0 1 10.5 9H14a.5.5 0 0 1 0 1h-.085q.084.236.085.5v1a2.5 2.5 0 0 1-5 0v-.14l-.21-.07a2.5 2.5 0 0 0-1.58 0l-.21.07v.14a2.5 2.5 0 0 1-5 0zm8.5-.5h2a.5.5 0 0 1 .5.5v1a1.5 1.5 0 0 1-3 0v-1a.5.5 0 0 1 .5-.5"/>
</svg>
</span>
<strong>Custom variant alert</strong><br>
This alert uses a custom variant and style.
</alert-element>
You can apply custom styles to the alert element using CSS custom properties and the ::part()
pseudo-element.
<style>
.custom-alert {
--alert-bg-color: #cfe2ff;
--alert-fg-color: #072c65;
--alert-border-color: #9ec5fe;
}
@media (prefers-color-scheme: dark) {
.custom-alert {
--alert-bg-color: #061633;
--alert-fg-color: #6ea8fe;
--alert-border-color: #0a4298;
}
}
.custom-alert::part(base) {
border-width: 1px;
}
.custom-alert::part(close) {
background-color: var(--alert-fg-color);
color: var(--alert-bg-color);
border-radius: 0.25rem;
padding: 0.25rem;
}
</style>
<alert-element open closable class="custom-alert">
<span slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" width="1.25em" height="1.25em" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2"/>
</svg>
</span>
This alert has custom styling applied to it.
</alert-element>
To display an alert as a toast notification, create the alert element and call its toast()
method.
For more information, check the documentation.
When checked, immediately cancels the active toast and starts a new one. Otherwise, if a toast is still active, any subsequent calls to toast()
will be ignored.
<button type="button" data-variant="info">Info</button>
<button type="button" data-variant="success">Success</button>
<button type="button" data-variant="neutral">Neutral</button>
<button type="button" data-variant="warning">Warning</button>
<button type="button" data-variant="danger">Danger</button>
<input type="checkbox" id="forceRestart">
<label for="forceRestart">Force restart</label>
<alert-element variant="info" duration="3000" closable>
This is an info toast notification.
</alert-element>
<alert-element variant="success" duration="3000" closable>
This is a success toast notification.
</alert-element>
<alert-element variant="neutral" duration="3000" closable>
This is a neutral toast notification.
</alert-element>
<alert-element variant="warning" duration="3000" closable>
This is a warning toast notification.
</alert-element>
<alert-element variant="danger" duration="3000" closable>
This is a danger toast notification.
</alert-element>
<script>
const variants = ['info', 'success', 'neutral', 'warning', 'danger'];
variants.forEach(variant => {
const button = document.querySelector(`button[data-variant="${variant}"]`);
const alert = document.querySelector(`alert-element[variant="${variant}"]`);
button.addEventListener('click', () => {
alert.toast({ forceRestart });
});
});
let forceRestart = false;
const restartCheckbox = document.querySelector('input[type="checkbox"]');
restartCheckbox.addEventListener('change', evt => {
forceRestart = evt.target.checked;
});
</script>
For convenience, you can create a utility function that creates a toast notification imperatively, instead of creating the alert elements in your markup.
To do this, you can generate the alert element using JavaScript and call the toast()
method on it.
For more information, check the documentation.
<button type="button">Create Toast</button>
<script>
const button = document.querySelector('button');
let count = 0;
button.addEventListener('click', () => {
toastify(`This is a custom toast alert #${++count}`, {
icon: `
<svg xmlns="http://www.w3.org/2000/svg" width="1.25em" height="1.25em" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
</svg>
`,
variant: 'info'
});
});
function toastify(message, options = {}) {
const defaults = {
duration: 3000,
variant: 'neutral',
icon: ''
};
options = { ...defaults, ...options };
const icon = options.icon ? `<span slot="icon">${options.icon}</span>` : '';
const alert = Object.assign(document.createElement('alert-element'), {
closable: true,
duration: options.duration,
variant: options.variant,
innerHTML: `${icon}${escapeHtml(message)}`
});
}
function escapeHtml(html) {
const div = document.createElement('div');
div.textContent = html;
return div.innerHTML;
}
</script>
You can customize the position of the toast stack by targeting the .alert-toast-stack
class in your stylesheet.
NOTE
In real-world applications, toast alerts should be displayed in a single position on the screen for better user experience. This example uses multiple positions for demonstration purposes only.
<style>
[data-toast-stack-position="top-right"] .alert-toast-stack::part(base) {
top: 0;
right: 0;
}
[data-toast-stack-position="top-center"] .alert-toast-stack::part(base) {
right: 50%;
transform: translateX(50%);
}
[data-toast-stack-position="top-left"] .alert-toast-stack::part(base) {
right: auto;
left: 0;
}
[data-toast-stack-position="bottom-left"] .alert-toast-stack::part(base) {
right: auto;
left: 0;
top: auto;
bottom: 0;
}
[data-toast-stack-position="bottom-center"] .alert-toast-stack::part(base) {
right: 50%;
transform: translateX(50%);
top: auto;
bottom: 0;
}
[data-toast-stack-position="bottom-right"] .alert-toast-stack::part(base) {
top: auto;
bottom: 0;
}
</style>
<input type="radio" id="top-right" value="top-right" name="name="toast-stack-poisiton" checked>
<label for="top-right">Top right</label>
<input type="radio" id="top-center" value="top-center" name="name="toast-stack-poisiton">
<label for="top-center">Top center</label>
<input type="radio" id="top-left" value="top-left" name="name="toast-stack-poisiton">
<label for="top-left">Top left</label>
<input type="radio" id="bottom-left" value="bottom-left" name="name="toast-stack-poisiton">
<label for="bottom-left">Bottom left</label>
<input type="radio" id="bottom-center" value="bottom-center" name="name="toast-stack-poisiton">
<label for="bottom-center">Bottom center</label>
<input type="radio" id="bottom-right" value="bottom-right" name="name="toast-stack-poisiton">
<label for="bottom-right">Bottom right</label>
<button type="button">Create Toast</button>
<script>
const button = document.querySelector('button');
const alert = Object.assign(document.createElement('alert-element'), {
variant: 'info',
duration: 3000,
closable: true
});
alert.addEventListener('alert-after-hide', () => {
document.body.removeAttribute('data-toast-stack-position');
});
button.addEventListener('click', () => {
const checkedRadio = document.querySelector('input[type="radio"]:checked');
const position = checkedRadio ? checkedRadio.value : 'top-right';
alert.textContent = `I'm positioned at ${position}.`;
alert.toast({ forceRestart: true });
document.body.setAttribute('data-toast-stack-position', position);
});
</script>
You can customize the animations of the alert element using the customAnimations
property.
For more information, check the documentation.
<button type="button">Show Alert</button>
<alert-element variant="info" duration="3000" closable>
This alert has custom animations applied to it.
</alert-element>
<script>
const button = document.querySelector('button');
const alert = document.querySelector('alert-element');
alert.customAnimations = {
show: {
keyframes: [
{ opacity: 0, transform: 'rotateX(90deg) scale(0.8)' },
{ opacity: 1, transform: 'rotateX(-10deg) scale(1.05)' },
{ opacity: 1, transform: 'rotateX(5deg) scale(0.97)' },
{ opacity: 1, transform: 'rotateX(0deg) scale(1)' }
],
options: {
duration: 600,
easing: 'cubic-bezier(0.22, 1, 0.36, 1)'
}
},
hide: {
keyframes: [
{ opacity: 1, transform: 'scale(1)' },
{ opacity: 0, transform: 'scale(0.8)' }
],
options: {
duration: 400,
easing: 'ease-in'
}
}
};
button.addEventListener('click', () => {
alert.show();
});
</script>
With invoker commands you can toggle alert's visibility in a declarative way using
command
and commandfor
attributes on a button element, targeting the alert element element by its id
attribute.
Control the alert's visibility using invoker commands:
--alert-show
- shows the alert element--alert-hide
- hides the alert element<button type="button" commandfor="myAlert" command="--alert-show">Show Alert</button>
<button type="button" commandfor="myAlert" command="--alert-hide">Hide Alert</button>
<alert-element variant="info" id="myAlert">
<strong>Alert with invoker commands</strong><br>
This alert uses invoker commands to toggle its visibility.
</alert-element>
Licensed under the The MIT License (MIT)