<div class="alert" data-id="123456" data-module="alert" data-type="warning" data-can-dismiss="true" data-expanded="false" data-cookie-name="reusable">
<div class="container">
<div class="alert__header">
<h2 class="alert__heading">Warning Alert</h2>
<button type="button" class="alert__toggle">
<span class="alert__hide">hide</span>
<span class="alert__show">show</span>
<svg viewBox="0 0 320 320">
<use xlink:href="#arrow-up" />
</svg>
</button>
<button type="button" class="alert__close">
close
<svg viewBox="0 0 320 320">
<use xlink:href="#close" />
</svg>
</button>
</div>
<div class="alert__content">
<div class="rtf">
<p>Fugiat irure reprehenderit elit magna occaecat dolore ut laborum tempor consequat minim exercitation Lorem dolor.</p>
</div>
</div>
</div>
</div>
<section class="alerts" data-module="alerts" data-endpoint="https://private-8bd5d4-reuselibraryalerts.apiary-mock.com/alerts" data-cookie-name="reusable">
</section>
<div class="alert" data-id="{{id}}" data-module="alert" data-type="{{type}}" data-can-dismiss="true" data-expanded="false" data-cookie-name="reusable">
<div class="container">
<div class="alert__header">
<h2 class="alert__heading">{{heading}}</h2>
<button type="button" class="alert__toggle">
<span class="alert__hide">{{hideButtonLabel}}</span>
<span class="alert__show">{{showButtonLabel}}</span>
{{>svg name="arrow-up" viewBox="0 0 320 320"}}
</button>
<button type="button" class="alert__close">
{{closeButtonLabel}}
{{>svg name="close" viewBox="0 0 320 320" }}
</button>
</div>
{{#if copy}}
<div class="alert__content">
<div class="rtf">{{{copy}}}</div>
</div>
{{/if}}
</div>
</div>
<section class="alerts" data-module="alerts" data-endpoint="https://private-8bd5d4-reuselibraryalerts.apiary-mock.com/alerts" data-cookie-name="reusable">
</section>
{
"heading": "Warning Alert",
"type": "warning",
"copy": "<p>Fugiat irure reprehenderit elit magna occaecat dolore ut laborum tempor consequat minim exercitation Lorem dolor.</p>",
"hideButtonLabel": "hide",
"showButtonLabel": "show",
"closeButtonLabel": "close",
"id": "123456"
}
import { Component } from '@verndale/core'
import Cookies from 'js-cookie'
import { open, close } from '../helpers'
/**
* `Alert`
*
*
* @example
* import { Alert } from '@verndale/front-end-components';
*
* class Foo {
* construction(){
*
* const Alert = new Alert('.alert');
* }
* }
*/
class Alert extends Component {
setupDefaults() {
this.dom = {
content: this.el.querySelector('.alert__content'),
toggle: this.el.querySelector('.alert__toggle'),
hide: this.el.querySelector('.alert__hide'),
show: this.el.querySelector('.alert__show'),
close: this.el.querySelector('.alert__close')
}
this.id = this.el.dataset.id
this.cookieName = this.el.dataset.cookieName
this.canDismiss = this.el.dataset.canDismiss
this.expanded = this.el.dataset.expanded
this.shouldDisplayAlert()
if (this.dom.content !== null) {
this.cookieNameToggle = `${this.id}_toggle`
this.shouldToggle()
}
this.setDismissibleButton()
this.setExpandedAlert()
}
shouldToggle() {
this.alertToggle = Cookies.get(this.cookieNameToggle)
if (this.alertToggle) {
Cookies.set(this.cookieNameToggle, false)
this.dom.toggle.setAttribute('aria-expanded', 'true')
} else {
Cookies.set(this.cookieNameToggle, true)
this.dom.toggle.setAttribute('aria-expanded', 'false')
}
this.handleToggle()
}
addListeners() {
if (this.dom.content) {
this.dom.toggle.addEventListener('click', this.handleToggle.bind(this))
}
if (this.dom.close) {
this.dom.close.addEventListener('click', this.handleClose.bind(this))
}
}
shouldDisplayAlert() {
this.alerts = Cookies.get(this.cookieName)
if (this.alerts) {
this.alerts = JSON.parse(this.alerts)
if (this.alerts.includes(this.id)) {
return this.el.remove()
}
} else {
this.alerts = []
}
open({
element: this.el,
onComplete: () => (this.el.style.height = 'auto')
})
}
setDismissibleButton() {
if (this.canDismiss !== 'true') {
this.dom.close.style.display = 'none'
return
}
this.dom.close.style.display = 'block'
}
setExpandedAlert() {
if (this.expanded === 'true') {
this.handleToggle()
open({
element: this.el,
onComplete: () => (this.dom.content.style.display = 'block')
})
return
}
this.dom.toggle.setAttribute('aria-expanded', false)
this.collapseAlert()
}
handleToggle() {
if (this.dom.toggle.getAttribute('aria-expanded') === 'true') {
this.dom.toggle.setAttribute('aria-expanded', false)
this.collapseAlert()
} else {
this.dom.toggle.setAttribute('aria-expanded', true)
this.expandAlert()
}
}
expandAlert() {
this.dom.content.style.display = 'block'
open({
element: this.dom.content,
onComplete: () => {
this.dom.content.focus()
this.dom.content.style.height = 'auto'
}
})
}
collapseAlert() {
close({
element: this.dom.content,
onComplete: () => {
this.dom.content.style.display = 'none'
}
})
}
handleClose() {
this.alerts.push(this.id)
close({
element: this.el,
onComplete: () => {
Cookies.set(this.cookieName, JSON.stringify(this.alerts))
this.el.remove()
}
})
}
}
export default Alert
import { Component } from '@verndale/core'
import Alert from './Alert'
import Cookies from 'js-cookie'
class Alerts extends Component {
setupDefaults() {
this.dom = {
header: document.querySelector('header')
}
this.getAlerts()
}
displaySectionAlerts(alerts) {
if (alerts.length < 1) {
this.el.style.display = 'none'
return
}
alerts
.filter((alert) => {
const closedAlerts = Cookies.get(this.el.dataset.cookieName)
if (closedAlerts) {
return !JSON.parse(closedAlerts).includes(alert.ID.Guid)
}
return true
})
.map((alert) => this.createAlertTemplate(alert))
.forEach((element) => {
this.el.appendChild(element)
})
}
createAlertTemplate(alert) {
const {
AlertType,
CanBeDismissed,
Heading,
LoadExpanded,
Message,
ValidFrom,
ValidTo,
ID
} = alert
const alertContainer = document.createElement('div')
alertContainer.dataset.id = ID.Guid
alertContainer.dataset.type = AlertType.DataId
alertContainer.dataset.canDismiss = CanBeDismissed
alertContainer.dataset.expanded = LoadExpanded
alertContainer.dataset.cookieName = 'reusable'
alertContainer.classList.add('alert')
alertContainer.innerHTML = `
<div class="container">
<div class="alert__header">
<h2 class="alert__heading">${Heading}</h2>
<button type="button" class="alert__toggle">
<span class="alert__hide">hide</span>
<span class="alert__show">show</span>
<svg viewBox="0 0 320 320">
<use xlink:href="#arrow-up" />
</svg>
</button>
<button type="button" class="alert__close">
close
<svg viewBox="0 0 320 320">
<use xlink:href="#close" />
</svg>
</button>
</div>
<div class="alert__content">
<div class="rtf">
${Message}
</div>
</div>
</div>`
new Alert(alertContainer)
return alertContainer
}
getAlerts() {
fetch(this.el.dataset.endpoint)
.then((response) => {
return response.json()
})
.then((alerts) => {
this.displaySectionAlerts(alerts)
})
}
}
export default Alerts
@import '../theme', 'variables';
.alert {
background-color: $alert-primary;
color: $alert-primary-font;
& + .alert {
margin-top: 10px;
}
&[data-type='critical'] {
background-color: $alert-critical;
}
&[data-type='warning'] {
background-color: $alert-warning;
}
}
.alert__header {
align-items: center;
display: flex;
}
.alert__heading {
flex-grow: 1;
font-size: 18px;
letter-spacing: 1px;
margin-bottom: 0;
text-transform: uppercase;
}
.alert__toggle,
.alert__close {
align-items: center;
color: inherit;
display: flex;
flex-shrink: 0;
font-size: 12px;
height: 50px;
padding: 0 20px;
text-transform: uppercase;
&.dismiss {
svg {
margin-left: 0;
}
}
svg {
fill: $alert-primary-font;
height: 10px;
margin-left: 5px;
transform: rotate(180deg);
transition: transform 0.3s;
width: 10px;
}
}
.alert__toggle {
&[aria-expanded='false'] {
.alert__hide {
display: none;
}
.alert__show {
display: inline-block;
}
}
&[aria-expanded='true'] {
.alert__hide {
display: inline-block;
}
.alert__show {
display: none;
}
svg {
transform: none;
}
}
}
.alert__close {
background-color: rgba(0, 0, 0, 0.1);
}
.alert__content {
display: none;
font-size: 14px;
padding: 4px 0 20px;
transition: height 0.3s;
will-change: height;
}
.alerts {
margin: 10px 0;
}
$alert-primary: map-get($theme-colors, 'primary') !default;
$alert-critical: map-get($theme-colors, 'critical') !default;
$alert-warning: map-get($theme-colors, 'warning') !default;
$alert-primary-font: #fff !default;
An alert is an element that displays a brief, important message in a way that attracts the user’s attention without interrupting the user’s task. Dynamically rendered alerts are automatically announced by most screen readers, and in some operating systems, they may trigger an alert sound. It is important to note that, at this time, screen readers do not inform users of alerts that are present on the page before page load completes.
Because alerts are intended to provide important and potentially time-sensitive information without interfering with the user’s ability to continue working, it is crucial they do not affect keyboard focus. The alert dialog is designed for situations where interrupting work flow is necessary.
Add the front-end-copmonent library to your project
yarn add @verndale/front-end-components
Import the style to your main style file in your project
@import '../../node_modules/@verndale/front-end-components/lib/alert/styles';
Copy and paste to your project any of the markup in the alert variations - you can find the markup in the HTML tab.
The component will already have a default style/theme set, so it will work out of the box. The alert has a set of variables that may be overriden, or you may choose to just override the actual styles in your project. It is recommended to use the overrides if you can as it will be less code in your project.
Below is the list of variables you can override. You may also find these in the Assets tab under _variables.scss
// Primary Alert
$alert-primary
// Critical Alert
$alert-critical
// Warning Alert
$alert-warning
// Alert font color
$alert-primary-font
You always need to set your overrides before the import of you component - for example:
$alert-primary: #808080;
$alert-primary-font: #101010;
@import '../../node_modules/@verndale/front-end-components/lib/alert/styles';