#Modals

Modals are CSS-powered prompts designed for any site.

#Structure

A modal comprises of these classes:

  • modal - the darkened translucent background around modal-content. Think of this as the modal container.
    • modal-content - the main dialog itself.
      • modal-header - header or title bar of the dialog.
      • modal-body - main contents of the dialog.
      • modal-footer - bottom portion of dialog.

#Basic

There is quite a lot of flexibility when it comes to building your modal dialog. Typically, the modal-header consists of some title and a close button, the modal-body has whatever content you want, and the modal-footer consists of buttons to act on a prompt.

There are 2 ways to interact with the modal: JavaScript or plain CSS.

#JS Powered Modal

This is the most straight forward approach for interacting with the modal. We can define a simple function to toggle the .modal--visible class on the modal to hide and show it.

<script>
function toggleModal() {
  // Toggle modal visibility
  const modal = document.querySelector('#example-modal');
  modal.classList.toggle("modal--visible");
}
</script>

<!-- Button to open/close modal -->
<button onclick="toggleModal()">Open Modal</button>

<div class="modal modal--visible" id="example-modal"><a onclick="toggleModal" class="modal-overlay close-btn" aria-label="Close"></a>
  <div class="modal-content" role="document">
    <div class="modal-header u-flex u-justify-space-between">
      <div class="modal-title">Modal Dialog</div>
      <div onclick="toggleModal()"
        aria-label="Close"><span class="icon" style="cursor: pointer;"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="times" class="u-inline-block fa-times w-2 h-4 fa-wrapper" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"></path></svg></span></div>
    </div>
    <div class="modal-body">
        <!-- Some code here -->
    </div>
    <div class="modal-footer u-text-right"><a onclick="toggleModal()"
        class="u-inline-block mr-1"><button class="btn--sm">Cancel</button></a><a onclick="toggleModal()"
        class="u-inline-block"><button class="btn-primary btn--sm">Share</button></a></div>
  </div>
</div>
#CSS Powered Modal

This section covers interacting with the modal via CSS and navigation events. This approach relies more on implicit behaviors that exist within the browser rather than specifying how the logic works yourself like with the JavaScript approach

Opening a Modal

To open a modal, a link must be used with the href set to be the id of the modal. For example, if I create a modal with id test-modal, then the href of the link to open the modal should be set to #test-modal.

<div class="modal" id="test-modal">
    <!-- Modal stuff -->
</div>

<a href="#test-modal">Open Modal</a>

Close Button Creation/Behavior

The close button can be created using the btn-close class, but the examples shown here, we will be using a FontAwesome glyph wrapped with a link.

<div class="modal" id="test-modal">
    <div class="modal-header u-flex u-justify-space-between">
        <a href="#anchor-to-background" aria-label="Close">
            <span class="icon">
                <i class="fa-wrapper fa fa-times"></i>
            </span>
        </a>
    </div>
</div>

Notice that the close link must be wrapped by an anchor tag containing an href to some HTML element. The value you put in this href will alter the close behavior of the modal dialog.

Return to Specific Div

<a href="#TAG-OUTSIDE" class="modal-overlay close-btn" aria-label="Close"></a>

Return to Top

<a href="#" class="modal-overlay close-btn" aria-label="Close"></a>

Keep Scroll Position

<a href="#NON-EXISTENT-DIV" class="modal-overlay close-btn" aria-label="Close"></a>

Below is an example of a basic modal dialog.

<div class="modal modal-animated--zoom-in" id="basic-modal">
    <a href="#searchModalDialog" class="modal-overlay close-btn" aria-label="Close"></a>
    <div class="modal-content" role="document">
        <div class="modal-header u-flex u-justify-space-between"><a href="#components" aria-label="Close"><span class="icon"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="times" class="u-inline-block fa-times fa-w-11 fa-wrapper" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"></path></svg></span></a>
            <div class="modal-title">Invite</div>
        </div>
        <div class="modal-body">
            <div class="r">
                <h3 class="font-alt font-light u-text-center">Invite people to project</h3></div>
            <div class="space"></div>
            <div class="input-control">
                <input type="text" class="input-contains-icon" placeholder="Search for team members"><span class="icon"></div>
            <div class="divider"></div>
            <div class="my-1">
                <div class="tile tile--center py-1 px-2 my-1" style="box-shadow: rgba(0, 0, 0, 0.06) 0px 3px 6px, rgba(0, 0, 0, 0.03) 0px 3px 6px;">
                    <div class="tile__icon">
                        <figure class="avatar text-white bg-teal-400" data-text="Jn"></figure>
                    </div>
                    <div class="tile__container">
                        <p class="tile__title m-0">John Newman</p>
                        <p class="tile__subtitle m-0">jnewman@gmail.com</p>
                    </div>
                    <div class="tile__buttons">
                        <button class="btn-success btn--sm uppercase"><span class="icon"></span></button>
                    </div>
                </div>
                <div class="tile tile--center py-1 px-2 my-1" style="box-shadow: rgba(0, 0, 0, 0.06) 0px 3px 6px, rgba(0, 0, 0, 0.03) 0px 3px 6px;">
                    <div class="tile__icon">
                        <figure class="avatar text-white bg-teal-500" data-text="Fw"></figure>
                    </div>
                    <div class="tile__container">
                        <p class="tile__title m-0">Franklin Watson</p>
                        <p class="tile__subtitle m-0">fwatsonm@gmail.com</p>
                    </div>
                    <div class="tile__buttons">
                        <button class="btn-success btn--sm uppercase"><span class="icon"></span></button>
                    </div>
                </div>
                <div class="tile tile--center py-1 px-2 my-1" style="box-shadow: rgba(0, 0, 0, 0.06) 0px 3px 6px, rgba(0, 0, 0, 0.03) 0px 3px 6px;">
                    <div class="tile__icon">
                        <figure class="avatar text-white bg-teal-600" data-text="Cr"></figure>
                    </div>
                    <div class="tile__container">
                        <p class="tile__title m-0">Cornelia Roberts</p>
                        <p class="tile__subtitle m-0">croberts@outlook.com</p>
                    </div>
                    <div class="tile__buttons">
                        <button class="btn-danger btn--sm uppercase"><span class="icon"></span></button>
                    </div>
                </div>
                <div class="tile tile--center py-1 px-2 my-1" style="box-shadow: rgba(0, 0, 0, 0.06) 0px 3px 6px, rgba(0, 0, 0, 0.03) 0px 3px 6px;">
                    <div class="tile__icon">
                        <figure class="avatar text-white bg-teal-700" data-text="Da"></figure>
                    </div>
                    <div class="tile__container">
                        <p class="tile__title m-0">Dominic Alvarado</p>
                        <p class="tile__subtitle m-0">dalvarado@yahoo.com</p>
                    </div>
                    <div class="tile__buttons">
                        <button class="btn-success btn--sm uppercase"><span class="icon"></span></button>
                    </div>
                </div>
                <div class="tile tile--center py-1 px-2 my-1" style="box-shadow: rgba(0, 0, 0, 0.06) 0px 3px 6px, rgba(0, 0, 0, 0.03) 0px 3px 6px;">
                    <div class="tile__icon">
                        <figure class="avatar text-white bg-teal-800" data-text="Sl"></figure>
                    </div>
                    <div class="tile__container">
                        <p class="tile__title m-0">Stanley Lim</p>
                        <p class="tile__subtitle m-0">slim@stanleylim.me</p>
                    </div>
                    <div class="tile__buttons">
                        <button class="btn-success btn--sm uppercase"><span class="icon"></span></button>
                    </div>
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <div class="form-section u-text-right">
                <a className="mr-1" href="#components">
                    <button class="btn btn--sm u-inline-block">Cancel</button>
                </a>
                <a href="#components">
                    <button class="btn-info btn--sm u-inline-block">Confirm</button>
                </a>
            </div>
        </div>
    </div>
</div>

#Sizes

Modals come in 3 sizes: modal-small, normal, and modal-large. Append these classes to modal to set the size. Note that these width constraints apply to .modal-content and not .modal as .modal-content is the dialog itself.

<!-- Small modal -->
    <div class="modal modal-small">
        <div class="modal-content">
            <!-- Stuff -->
        </div>
    </div>
<!-- Normal modal -->
<div class="modal">
    <div class="modal-content">
        <!-- Stuff -->
    </div>
</div>
<!-- Small modal -->
<div class="modal modal-large">
    <div class="modal-content">
        <!-- Stuff -->
    </div>
</div>

#Animations

Modals have 3 animations: modal-animated--dropdown, modal-animated--zoom-in, and modal-animated--zoom-out. Append these classes to modal to set the animation mode.

<!-- Drop down modal -->
    <div class="modal modal-animated--dropdown">
        <div class="modal-content">
            <!-- Stuff -->
        </div>
    </div>
<!-- Zoom in modal -->
<div class="modal modal-animated--zoom-in">
    <div class="modal-content">
        <!-- Stuff -->
    </div>
</div>
<!-- Zoom out modal -->
<div class="modal modal-animated--zoom-out">
    <div class="modal-content">
        <!-- Stuff -->
    </div>
</div>

#Accessibility

To be complaint with WAI-ARIA Best Practices, you can easily include this snippet of JavaScript to close all dialogs when hitting the escape key.

document.addEventListener('keyup', function(e) {
    if(e.key === "Escape") {
        const modals = document.querySelectorAll('.modal-overlay');
        for (const modal of modals) {
            modal.click();
        }
    }
});