<div class="alert" data-id="123" data-module="alert" data-type="critical" data-can-dismiss="true" data-expanded="false" data-cookie-name="reusable">
    <div class="container">
        <div class="alert__header">
            <h2 class="alert__heading">Critical 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": "Critical Alert",
  "type": "critical",
  "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": "123"
}
  • Content:
    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
    
  • URL: /components/raw/alert/Alert.js
  • Filesystem Path: src/components/alert/Alert.js
  • Size: 3.4 KB
  • Content:
    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
    
  • URL: /components/raw/alert/Alerts.js
  • Filesystem Path: src/components/alert/Alerts.js
  • Size: 2.4 KB
  • Content:
    @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;
    }
    
  • URL: /components/raw/alert/_styles.scss
  • Filesystem Path: src/components/alert/_styles.scss
  • Size: 1.4 KB
  • Content:
    $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;
    
  • URL: /components/raw/alert/_variables.scss
  • Filesystem Path: src/components/alert/_variables.scss
  • Size: 218 Bytes

Alert

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.

Usage

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.


Styling

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';