Figuration v4.4 is now available!

Modal modal.js

The Modal widget allows you to add dialog style windows to your site or application.

Important Notes

  • Modals get positioned over everything else in the document and remove scroll from the <body> so that modal content scrolls instead.
  • By default, clicking on the modal "backdrop" will automatically close the modal.
  • Figuration only supports one modal at a time. Nested modals are not supported, as this can cause difficult usability and accessibility issues.
  • Modals use position: fixed. Always try to place modal HTML code in a top-level position in your document, such as a direct chld of the <body> element. Putting modal HTML within a fixed position element will adversely affect placement.
  • There are some caveats regarding using modals on mobile devices. See our browser support docs for details.
  • Embedding YouTube videos in modals requires additional JavaScript, not included in Figuration, to automatically stop playback and more. See this helpful Stack Overflow post for more information.
  • The autofocus HTML attribute has no effect in modals. To achieve the same effect you will need some custom JavaScript:
$('#myModal').on('afterShow.cfw.modal', function() {
$('#myInput').trigger('focus');
});

Examples

Below is a static modal example (meaning its position and display have been overridden). Included are the modal header, modal body (required for padding), and modal footer (optional). It is highly suggested to include modal headers with dismiss actions whenever possible, or provide another explicit dismiss action.

<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<p>Modal body content&hellip;</p>
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

Live Demo

Toggle a modal via JavaScript by clicking the button below. It will slide down and fade in from the top of the page. Examples of tooltips, popover, and scroll handling included.

<!-- Button trigger -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalLive">
Launch demo modal
</button>

<!-- Modal -->
<div class="modal" id="modalLive">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

Scrolling Long Content

When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below for an example.

<!-- Button trigger -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalScroll">
Scrolling modal
</button>

<!-- Modal -->
<div class="modal" id="modalScroll">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

Scrollable Body

Add .modal-dialog-scrollable to .modal-dialog where the .modal-body is the scrollable region, and the entire modal fits within the viewport height.

<!-- Button trigger -->
<button type="button" class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalScrollBody">
Scrollable modal body
</button>

<!-- Modal -->
<div class="modal" id="modalScrollBody">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

Vertically Centered

Add .modal-dialog-centered to .modal-dialog to vertically center the modal.

<!-- Button trigger -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalCenter">
Centered modal
</button>

<!-- Modal -->
<div class="modal" id="modalCenter">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

A vertically centered dialog will also scroll when the content is longer than the viewport.

<!-- Button trigger -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalCenterScroll">
Scrolling centered modal
</button>

<!-- Modal -->
<div class="modal" id="modalCenterScroll">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

You can also combine .modal-dialog-centered with .modal-dialog-scrollable to keep the modal within the viewport height.

<!-- Button trigger -->
<button type="button" class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalCenterBody">
Centered, scrolling modal body
</button>

<!-- Modal -->
<div class="modal" id="modalCenterBody">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-cfw-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-cfw-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

Grid Usage

To take advantage of the grid system within a modal, just nest .container-fluid within the .modal-body and then use the normal grid system classes within this container.

<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4 offset-md-4">.col-md-4 .offset-md-4</div>
</div>
<div class="row">
<div class="col-md-3 offset-md-3">.col-md-3 .offset-md-3</div>
<div class="col-md-2 offset-md-4">.col-md-2 .offset-md-4</div>
</div>
<div class="row">
<div class="col-md-6 offset-md-3">.col-md-6 .offset-md-3</div>
</div>
<div class="row">
<div class="col-sm-9">
Level 1: .col-sm-9
<div class="row">
<div class="col-8 col-sm-6">
Level 2: .col-8 .col-sm-6
</div>
<div class="col-4 col-sm-6">
Level 2: .col-4 .col-sm-6
</div>
</div>
</div>
</div>
</div>
</div>

Tooltips and Popovers

Tooltips and popovers can be placed within modal as needed. When modals are closed, any tooltips or popovers within are also automatically dismissed.

<div class="modal-body">
<h5>Popover in a modal</h5>
<p>This <a href="#" role="button" class="btn" title="Popover title" data-cfw="popover" data-cfw-popover-content="Popover body content is set in this attribute." data-cfw-popover-placement="forward">button</a> triggers a popover on click.</p>
<hr>
<h5>Tooltips in a modal</h5>
<p><a href="#" title="Tooltip" data-cfw="tooltip">This link</a> and <a href="#" title="Tooltip" data-cfw="tooltip">that link</a> have tooltips on hover.</p>
</div>

Optional Sizes

Modals have two optional sizes, provided by Figuration's base CSS, available via modifier classes to be placed on a .modal-dialog.

<!-- Large modal -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalLg">Large modal</button>

<div class="modal" id="modalLg">
<div class="modal-dialog modal-lg">
<div class="modal-content">
...
</div>
</div>
</div>

<!-- Small modal -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalSm">Small modal</button>

<div class="modal" id="modalSm">
<div class="modal-dialog modal-sm">
<div class="modal-content">
...
</div>
</div>
</div>

Side Aligned

Position a modal to the side of the page with a .modal-dialog-side-start or .modal-dialog-side-end modifier class placed on a the .modal-dialog. Side aligned modals can be used with .modal-dialog-scrollable, and can also use the sizing classes.

<!-- Large modal -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalSideStart">Start side modal</button>

<div class="modal" id="modalSideStart">
<div class="modal-dialog modal-dialog-side-start">
<div class="modal-content">
...
</div>
</div>
</div>

<!-- Small modal -->
<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalSideEnd">End side modal</button>

<div class="modal" id="modalSideEnd">
<div class="modal-dialog modal-dialog-side-end modal-dialog-scrollable modal-sm">
<div class="modal-content">
...
</div>
</div>
</div>

Static Backdrop

When backdrop option is set to static, the modal will not close when clicking outside it. Click the button below to try it.

<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-backdrop="static" data-cfw-modal-target="#modalStaticBackdrop">Static backdrop modal</button>

<div class="modal" id="modalStaticBackdrop">
<div class="modal-dialog modal-dialog-side-end modal-dialog-scrollable modal-sm">
<div class="modal-content">
...
</div>
</div>
</div>

Fullscreen Modal

Enlarge a modal to fill the entire viewport with a .modal-fullscreen modifider class placed on the .modal-dialog.

<button class="btn btn-primary" data-cfw="modal" data-cfw-modal-target="#modalFullscreen">Fullscreen modal</button>

<div class="modal" id="modalFullscreen">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
...
</div>
</div>
</div>

Responsive variants are also available. These work for a given breakpoint and below with the form .modal-fullscreen-{breakpoint}-down.

Heads up! There is no .modal-fullscreen-*-down class created for the largest breakpoint since it is functionally equivalent to using .modal-fullscreen.

<!-- Fullscreen modal at `xs` breakpoint -->
<div class="modal-dialog modal-fullscreen-xs-down">
...
</div>

<!-- Fullscreen modal at `sm` breakpoint and below -->
<div class="modal-dialog modal-fullscreen-sm-down">
...
</div>

<!-- Fullscreen modal at `md` breakpoint and below -->
<div class="modal-dialog modal-fullscreen-md-down">
...
</div>

<!-- Fullscreen modal at `lg` breakpoint and below -->
<div class="modal-dialog modal-fullscreen-lg-down">
...
</div>

You can also combine fullscreen variants with the centered and scrollable variants. The fullscreen version of the modal will then assume a similar scrolling behavior to match, but centering will not occur since the modal will be stretched to the size of the viewport.

<!-- Fullscreen modals at `md` breakpoint and below -->

<!-- Scrollable body above `md` breakpoint -->
<div class="modal-dialog modal-fullscreen-md-down modal-dialog-scrollable">
...
</div>

<!-- Centered above `md` breakpoint -->
<div class="modal-dialog modal-fullscreen-md-down modal-dialog-centered">
...
</div>

<!-- Centered and scrollable body above `md` breakpoint -->
<div class="modal-dialog modal-fullscreen-md-down modal-dialog-centered modal-dialog-scrollable">
...
</div>

Usage

The modal widget toggles your hidden content on demand, via data attributes or JavaScript. It also adds .modal-open to the <body> to override default scrolling behavior and generates a .modal-backdrop to provide a click area for dismissing shown modals when clicking outside the modal.

Via Data Attributes

Activate a modal without writing JavaScript. Set data-cfw="modal" on a controller element, like a button, along with a data-cfw-modal-target="#foo" or href="#foo" to target a specific modal to toggle.

<button type="button" data-cfw="modal" data-cfw-modal-target="#foo">Launch modal</button>

Via JavaScript

Call a modal with id myModal with a single line of JavaScript:

$('#myModal').CFW_Modal();

Close Triggers

Any an element with a data attribute of data-cfw-dismiss="modal" within the modal element will act as a close trigger for the modal. There can be multiple close triggers, such as a header/titlebar close and a cancel button in the footer.

Alter Animation

In Sass settings, The $modal-transform-fade setting determines the transform state of .modal-dialog before the modal fade-in animation, the $modal-transform-in setting determines the transform of .modal-dialog at the end of the modal fade-in animation.

If you want for example a zoom-in animation, you can set $modal-transform-fade: scale(.75).

Dynamic Heights

If the height of a modal changes while it is open, you will need to call $('#myModal').CFW_Modal('handleUpdate'); to readjust the modal's position and backdrop.

With Fixed Position Content

Since the scrollbar is removed from the <body> when a modal is shown, there can be some shifting of content in fixed position elements. To help with this issue, when a modal is shown, any elements using the fixed positioning utility classes, (.fixed-top and .fixed-bottom), will have additional padding added to their right side. This padding width should match the width of the scrollbar that becomes hidden. When the modal is hidden, the padding-right CSS value will be reset.

There is also an additional special classname that the modal widget will look for when adjusting padding values. Simply add the .is-fixed class to your element, and it will automatically be handled.

Options

Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-cfw-modal-, as in data-cfw-modal-animate=false.

Name Type Default Description
target string null The selector of the target modal.
animate boolean true If modal targets should fade and slide in.
unlink boolean false If the unlink method should be called when the modal is hidden. This leaves the modal behind in the DOM.
dispose boolean false If the dispose method should be called when the modal is hidden. This will remove the modal from the DOM.
backdrop boolean or the string 'static' true

Includes a modal-backdrop element. Alternatively, specify 'static' for a backdrop which doesn't close the modal on click.

The backdrop is the semi-opaque overlay used to visually seperate the modal from the page content.

keyboard boolean true Closes the modal when escape key is pressed.
show boolean false Shows the modal when initialized.
$('#myModal').CFW_Modal({
animate: false
});

Methods

Method calls can be made on either the trigger or the target <div class="modal"> element.

Method Name Description
toggle Toggles a modal dialog to be shown or hidden.
show Shows a modal dialog.
hide Hides a modal dialog.
unlink Hides the modal, removes events and attributes from both trigger and modal.
dispose Calls the unlink method, and then removes the modal from the DOM.
$('#myModal').CFW_Modal('show');

Events

Event callbacks happen on the target <div class="modal"> element.

Event Type Description
init.cfw.modal This event fires after the modal item is initialized.
beforeShow.cfw.modal This event is fired immediately when the show method is called.
scrollbarSet.cfw.modal This event is fired immediately when the <body> padding is adjusted for the scrollbar width.
afterShow.cfw.modal This event is fired when a modal dialog has been made visible to the user (will wait for CSS transitions to complete).
scrollbarReset.cfw.modal This event is fired immediately when the <body> padding adjustment for the scrollbar is removed.
beforeHide.cfw.modal This event is fired immediately when the hide method is called.
afterHide.cfw.modal This event is fired when a modal dialog has been hidden from the user (will wait for CSS transitions to complete).
beforeUnlink.cfw.modal This event is fired immediately when the unlink method is called. This event can occur after the `beforeHide` event if set to automatically unlink, or before if called via method.
afterUnlink.cfw.modal

This event is fired when a modal item has been unlinked from its trigger item and the data-api removed. This event can occur after the afterHide event when invoked from the unlink method, or before if set to automatically unlink.

This event may need to be listened for using event delegation, since all cfw.modal namespaced events will be detached from the trigger element as part of the unlink process.

dispose.cfw.modal

This event is fired immediately before the modal item is removed from the DOM.

This event may need to be listened for using event delegation, since all cfw.modal namespaced events will be detached from the trigger element as part of the unlink process.

$('#myModal').on('afterHide.cfw.modal', function() {
// do something...
});

Server-side Apps

Modals are designed to hopefully work with server side applications, such as Apache Wicket, and other instances where the server-side application might need to create or update the modal content after the initial page load.

A quick example:

  1. An item with an event handler that makes a callback to create a new modal is interacted with.
  2. Call as needed:
    • $('#myModal').CFW_Modal('hide');
    • or $('#myModal').CFW_Modal('unlink');
    • or $('#myModal').CFW_Modal('dispose');
  3. Update/create the modal object and insert into DOM.
  4. Initialize the modal: $('#myModal').CFW_Modal(options); with desired options.
  5. Show modal: $('#myModal').CFW_Modal('show');

Accessibility

It is recommended that a .modal-title item is used, even if visually hidden, within the modal since it will be automatically be found and linked with an aria-labelledby on the .modal container. This provides a potential description of the modal to screen-reader users when the modal is shown and focus is automatically moved to the .modal container.

Key Commands

The following key commands are handled when focus is inside the modal:

  • Esc - Close the modal

Enforced Focus

In order to keep assistive technology users from interacting with the rest of the page when a modal is open, the focus is automatically forced back to the modal when a user tries to navigate out.

When navigating forward, out the bottom of the modal, focus will be moved to the top of the modal.

When navigation backward, out the top of the modal, focus will be moved back to the top of the modal.

If for some reason you need to disable the enforced focus for modals, you can override the enforceFocus() method.

// This needs to be loaded after Figuration's JavaScript
// PLEASE DO NOT DO THIS!!! - Just here for reference
$.fn.CFW_Modal.Constructor.prototype.enforceFocus = function() {};
// SERIOUSLY DO NOT DO THIS!!!

However, we do not advise disabling it completely, but overriding the function to handle the focus conditionally.

// This needs to be loaded after Figuration's JavaScript
$.fn.CFW_Modal.Constructor.prototype.enforceFocus = function() {
var $selfRef = this;
$(document)
.off('focusin.cfw.modal') // guard against infinite focus loop
.on('focusin.cfw.modal', function(event) {
if (document !== event.target && $selfRef.$targetElm[0] !== event.target && !$selfRef.$targetElm.has(event.target).length)
// Add conditions here
// In this case items with a 'focusuable-item' class
&& !$(event.target.parentNode).hasClass('focusuable-item') {
$selfRef.$targetElm.trigger('focus');
}
});
}
};

SASS Reference

Variables

The available Customization options, or Sass variables, that can be customized for the modal component.

Name Type Default Description
$enable-modal boolean true Enable the generation of the modal component classes. Smaller segements of the modal component classes can be disabled with the following $enable-* variables.
$enable-modal-centered boolean true Enable the generation of the vertically centered modal variant.
$enable-modal-scrollable boolean true Enable the generation of the scrollable body modal variant.
$enable-modal-side-start boolean true Enable the generation of the start side aligned modal variant.
$enable-modal-side-end boolean true Enable the generation of the end side aligned modal variant.
$enable-modal-fullscreen boolean true Enable the generation of the fullscreen modal variant.
$enable-modal-fullscreen-responsive boolean true Enable the generation of the responsive fullscreen modal variants.
$enable-modal-header boolean true Enable the generation of the modal header class.
$enable-modal-title boolean true Enable the generation of the modal title class.
$enable-modal-body boolean true Enable the generation of the modal body class.
$enable-modal-footer boolean true Enable the generation of the modal footer class.
$modal-dialog-margin string .625rem Spacing around modal dialog.
$modal-dialog-bp-up-margin-y string .625rem Vertical spacing for modal dialog starting at the breakpoint defined by $modal-breakpoint.
$modal-content-bg string $component-bg Background color for modal content container.
$modal-content-border-color string $component-overlay-border-color Border color for modal content container.
$modal-content-border-width string $border-width Border width for modal content container.
$modal-content-box-shadow string map-get($shadows, "d3") Box shadow for modal content container.
$modal-content-bp-up-box-shadow string map-get($shadows, "d4") Box shadow for modal content container at the breakpoint defined by $modal-breakpoint.
$modal-border-radius string .375rem Border radius for modal content container.
$modal-inner-border-radius string calc(#{$modal-border-radius} - #{$modal-content-border-width}) Border radius for modal header and footer.
$modal-backdrop-bg string $dark Background color for modal backdrop.
$modal-backdrop-opacity string .5 Opacity for modal backdrop.
$modal-header-padding-y string .75rem Vertical padding for modal header.
$modal-header-padding-x string 1rem Horizontal padding for modal header.
$modal-header-color string null Text color for modal header.
$modal-header-background-color string null Background color for modal header.
$modal-header-border-color string rgba($uibase-900, .2) Border color for modal header.
$modal-header-border-width string $modal-content-border-width Border width for modal header.
$modal-title-line-height string $line-height-base Line height for modal header.
$modal-close-padding-y string .75rem Vertical padding for close button in modal header.
$modal-close-padding-x string .75rem Horizontal padding for close button in modal header.
$modal-body-padding-y string .75rem Vertical padding for modal body.
$modal-body-padding-x string 1rem Horizontal padding for modal body.
$modal-footer-padding-y string .75rem Vertical padding for modal footer.
$modal-footer-padding-x string 1rem Horizontal padding for modal footer.
$modal-footer-color string null Text color for modal footer.
$modal-footer-background-color string null Background color for modal footer.
$modal-footer-border-color string $modal-header-border-color Border color for modal footer.
$modal-footer-border-width string $modal-header-border-width Border width for modal footer.
$modal-sm string rem(304px) (19rem) Max width for small modal dialog variant.
$modal-md string rem(528px) (33rem) Max width for modal dialog starting at the breakpoint defined by $modal-breakpoint.
$modal-lg string rem(896px) (56rem) Max width for large modal dialog variant.
$modal-breakpoint string sm When to start scaling up modal width and margins.
$modal-lg-breakpoint string lg The minimum breakpoint to allow .modal-lg.
$modal-transform-fade string translate(0, -3rem) Transform state of .modal-dialog before the modal fade-in animation
$modal-transform-in string none Transform state of .modal-dialog at the end of the modal fade-in animation.
$modal-transform-side-offset string -5rem Transform state offset of .modal-dialog before the modal fade-in animation for side variant modals.
$modal-transform-blocked string scale(1.01) Transform state of .modal-dialog for when the close is blocked animation.
$modal-transform-fullscreen string none Transform state of .modal-dialog for the slide animation when the modal in fullscreen mode.
$modal-transition string transform .15s linear Transition settings for the .modal-dialog animations.
$modal-fullscreen-breakpoints list map-keys($grid-breakpoints) Breakpoint list for responsive fullscreen modals.

Mixins

Enable fullscreen mode on a .modal-dialog.

@include modal-fullscreen();