Popup

The popup is an overlay containing various UI elements and a Call to Action which fully grabs the user's attention.

Popup windows are custom made modals that block interaction with the rest of the page and prompt the user with an immediate action before they can proceed.

It has a title and an optional large icon icon in the header, some contextual information and up to two actions like "OK" and "Cancel" or "Accept" and "Decline".

Please note that on the current stage we provide the layout only, javascript parts in the code example are only there for presentational purposes and will be replaced with actual plugin code once it's available. Therefore all of the modal functionalities described here must be implemented by the developer.

Plugin

Using the popup plugin is easy and will handle most of the javascript hard work for you:

If you configure it correctly, the plugin will take care of all of this for you:

  • Adding the right role="dialog" and aria-modal="true" to the popup;
  • Toggling the hidden and --active modifiers to show and hide the popup with a small interval to enable the animation to run smoothly;
  • Adding ESC key press support for closing the popup with the keyboard;
  • Creating a tab trap that doesn't allow the user to tab away from the popup (cycles tabs from the first and the last focusable items);
  • Adding tabindex="0" to the content section if it has a scroll to enable keyboard users to focus the content in order to scroll it with arrow keys;
  • Adding the close button click handler if a close button is present;

To configure the popup to use the plugin follow these steps:

  1. Include the plugin from our CDN at the header of your page:
<script src="https://honeycomb.flixbus.com/dist/{VERSION_TAG}/js/popup.js"></script>
  1. Initialize the plugin at the end:
document.addEventListener("DOMContentLoaded", function() {
  popup.init();
});
  1. Add an id to the flix-popup element and initialize it with the hidden attribute, so it's closed;
  2. Use the popup id and connect it to the toggle by using data-popup="{THE_POPUP_ID}";
  3. Accessibility guidelines dictates that all dialogs must have a label:
  • You can either give the popup and aria-label;
  • Or you can associate the popup title with and id and aria-labelledby;

The example bellow shows a popup with icon and two actions.

<button type="button" class="flix-btn flix-btn--primary" data-popup="js-popup-example-1">
  Click me and I will open a Popup!
</button>

<div id="js-popup-example-1" class="flix-popup" aria-labelledby="popup-example-title" hidden="">
  <div class="flix-popup__body">
    <div class="flix-popup__icon">
      <flix-icon name="time" size="12" aria-label="Clock" role="img"></flix-icon>
    </div>
    <h2 class="flix-popup__title" id="popup-example-title">
      Your time is up!
    </h2>
    <div class="flix-popup__content">
      Everything is lost, there is no chance you can fix this mess!
      Be honest with yourself and surrender!
    </div>
    <div class="flix-popup__actions">
      <button type="button" class="flix-btn">
        Oh my god!
      </button>
      <button type="button" class="flix-btn flix-btn--primary">
        Keep trying
      </button>
    </div>
  </div>
  <div class="flix-overlay"></div>
</div>

The example bellow has only one action.

<button type="button" class="flix-btn flix-btn--primary" data-popup="js-popup-example-2">
  Click me and I will open a Popup!
</button>

<div id="js-popup-example-2" class="flix-popup" aria-labelledby="popup-example-2-title" hidden="">
  <div class="flix-popup__body">
    <h2 class="flix-popup__title" id="popup-example-2-title">
      Your time is up!
    </h2>
    <div class="flix-popup__content">
      Everything is lost, there is no chance you can fix this mess!
      Be honest with yourself and surrender!
    </div>
    <div class="flix-popup__actions">
      <button type="button" class="flix-btn flix-btn--primary">
        Keep trying
      </button>
    </div>
  </div>
  <div class="flix-overlay"></div>
</div>

Scrollable content:

The content section is the only scrollable area of the popup. By default the actions, icon and title are fixed when the popup has a lot of content.

You can make the icon and title scroll with the content by moving them inside of the content section.

  • Icon and title outside of content section: stay visible fixed when scrolling content
  • Icon and title inside of content section: move with the content when scrolling
  • The Actions should be always outside of the content section, and visible

When your popup has enough content that it needs to scroll, the content area should focusable, so that a user that is using the keyboard can tab into it and scroll the content using the arrow keys. Otherwise it will be impossible for said user to scroll the content. To do so, the popup adds tabindex="0" to the content section.

<button type="button" class="flix-btn flix-btn--primary" data-popup="js-popup-example-3">
  Click me for a long Terms and Conditions popup
</button>

<div id="js-popup-example-3" class="flix-popup" aria-labelledby="popup-example-3-title" hidden="">
  <div class="flix-popup__body">
    <div class="flix-popup__content">
      <div class="flix-popup__icon">
        <flix-icon name="document" size="8" aria-label="Document" role="img"></flix-icon>
      </div>
      <h2 class="flix-popup__title" id="popup-example-3-title">
        Terms and Conditions
      </h2>
      <p class="flix-text">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Eaque, esse earum deserunt aliquid similique iure minus enim repellendus molestiae nam, facere voluptatem vero quisquam sequi vitae! Laboriosam quaerat voluptatibus soluta.
      </p>
      <p class="flix-text">
        Doloribus laborum, a, aut quasi provident sint ipsum labore aperiam laudantium hic corrupti mollitia fugit numquam suscipit reiciendis vel soluta? Aspernatur reiciendis ex tempore! Et nobis possimus praesentium consequuntur repellendus?
      </p>
      <p class="flix-text">
        Pariatur, consequuntur consequatur quod labore, molestias accusantium soluta odio ut deserunt enim commodi, iure necessitatibus officiis animi magni quasi asperiores fugiat? Fugiat, debitis natus minima temporibus a delectus consectetur quam!
      </p>
      <p class="flix-text">
        Ea sint ipsam maiores officia nisi, voluptate dolores corrupti adipisci unde a suscipit at natus neque autem id deserunt ex vel alias minus facere odio quas doloribus dicta. Atque, praesentium?
      </p>
      <p class="flix-text">
        Minus reprehenderit excepturi iste, harum illo officia iusto quo, recusandae eos ex eum vel quidem. Ea corrupti voluptatibus illo fugiat aliquam, illum repellendus nihil nulla provident inventore rerum perferendis tempore?
      </p>
      <p class="flix-text">
        Pariatur a minima quo repellat, optio adipisci error cum consequatur totam animi vitae velit libero blanditiis reprehenderit ut quisquam, laborum quaerat assumenda quibusdam sed tempore, nobis alias saepe? Omnis, sit!
      </p>
      <p class="flix-text">
        Veniam pariatur quidem neque tempora, illum sunt tempore suscipit perspiciatis sed consectetur laborum accusantium omnis labore impedit dolore. Ea perspiciatis facilis ratione neque. Quas ipsam quos, tenetur suscipit vero aliquid.
      </p>
      <p class="flix-text">
        Cupiditate excepturi labore perferendis autem beatae dolorum veniam quia sequi doloremque itaque facere unde nemo dolores id obcaecati quaerat, culpa ducimus architecto iste illo assumenda. Reprehenderit quis sunt numquam tempora.
      </p>
      <p class="flix-text">
        Quas officiis laudantium repellendus consequuntur eaque consequatur voluptate. Ratione eum, molestiae debitis cum, accusamus, a modi hic alias necessitatibus assumenda consectetur. Officiis reiciendis, nemo labore suscipit assumenda dolores delectus doloribus?
      </p>
      <p class="flix-text">
        Placeat, commodi! Ex, nesciunt nobis vitae consequuntur repellat eius explicabo maxime excepturi quis, dolorum a incidunt ducimus laudantium nam iure. Cupiditate voluptatum saepe nobis quibusdam ex adipisci porro sapiente labore?
      </p>
      <p class="flix-text">
        Hic tempore, eos neque, quas maiores maxime ut labore, dolorum culpa illum consectetur in quae autem. Quod, itaque repellat ratione mollitia dolor consequatur expedita delectus enim dicta exercitationem quis eius.
      </p>
    </div>
    <div class="flix-popup__actions">
      <button class="flix-btn">Cancel</button>
      <button class="flix-btn flix-btn--primary">I Agreed</button>
    </div>
  </div>
  <div class="flix-overlay"></div>
</div>

Making it work without the plugin

Popup modals require you to provide an overlay element that will cover the page and block the user from interacting with elements outside of the popup. You must implement a "tab trap" and also disable the window scroll when the panel is open.
- Add `role="dialog"` and `aria-modal-"true"` to the popup element for accessibility;
- Add an `id` to the title and pass it as `aria-labelledby` value to the popup to give the dialog a proper name;
- Add the `flix-overlay` element at the end of the popup;
- Adding `tabindex="0"` to the content if it has a lot of content and can show a scroll bar to enable keyboard users to also scroll the content with arrow keys;

- **Opening the popup:**
  - Move focus to the first element of the popup;
  - Create a "tab trap" so when users tab on the last element it returns focus to the first, and vice versa;
  - Block users from scrolling the page outside by adding `overflow: hidden;` CSS rule to the body element;

- **Closing the popup:**
  - Allow users to close the popup by clicking the overlay or pressing <kbd>ESC</kbd>;
  - Move focus back to the element that triggered the popup;
  - Remove the `overflow: hidden'` CSS rule from the body;