The Modal augments the Bootstrap Modal. The Modal will be appended to the body element when opened.
Add the class .vi-modal to the dialog wrapper and only use .modal-body.
Never use .modal-header or .modal-footer. The design requires more fine grained control over the layout.
To have full control over the layout inside .modal-body the Modal Layout is used.
The Modal is basically a restyled version of the Bootstrap Modal. For al options please visit their website.
<!-- .d-block, .position-static and .show classes to display a static modal example -->
<!-- Modal -->
<div class="modal fade d-block position-static show vi-modal" role="dialog" tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout -->
<div class="vi-modal-layout">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<h3>Wayfarers diy 8-bit.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="vi-typesystem">
<p>Vegan small batch messenger bag. Heirloom park keffiyeh five dollar toast. Disrupt tousled roof swag vice church-key.</p>
</div>
<div class="text-center">
<!-- Button type: solid -->
<button data-dismiss="modal" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Truffaut authentic</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Toggle a working modal demo by clicking the button below. It will slide down and fade in from the top of the page.
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-d42b8a" type="button" class="vi-btn-solid vi-btn">Launch text content</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-d42b8a" role="dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout -->
<div class="vi-modal-layout">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<h3>Retro letterpress cronut.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="vi-typesystem">
<p>Pug tote bag flexitarian leggings. Distillery narwhal pitchfork. Salvia yr direct trade tote bag photo booth health chia.</p>
</div>
<div class="text-center">
<!-- Button type: solid -->
<button data-dismiss="modal" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Lomo polaroid</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-9955db" type="button" class="vi-btn-solid vi-btn">Launch video content</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-9955db" role="dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout (mods: --compact) -->
<div class="vi-modal-layout vi-modal-layout--compact">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<p>Literally keytar try-hard.</p>
</div>
<div class="vi-modal-layout__close">
<!-- Button type: close -->
<button aria-label="Message dialog - click to close or navigate to the message content" data-dismiss="modal" type="button" class="vi-btn-close vi-btn-close--accent-1 vi-btn"><span class="vi-btn-close__label vi-btn__label">Close</span></button>
</div>
</div>
</div>
</div>
<!-- Modal Layout (mods: --visual) -->
<div class="vi-modal-layout vi-modal-layout--visual">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--video">
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" src="https://www.youtube.com/embed/672TY8K2PKk"></iframe>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-9e275a" type="button" class="vi-btn-solid vi-btn">Launch modal with scrollpane</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-9e275a" role="dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout -->
<div class="vi-modal-layout">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<h3>Yolo tofu post-ironic.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="mb-20" style="height: calc(var(--vh) * 25)">
<!-- Scrollpane -->
<div class="vi-scrollpane">
<div class="vi-scrollpane__bar">
...
...
...
...
...
</div>
</div>
</div>
<div class="text-center">
<!-- Button type: solid -->
<button data-dismiss="modal" id="sg-9e275afocus-test" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Ethical asymmetrical</button>
</div>
</div>
</div>
</div>
<script>
// Window on key t down, focus element with id 'focus-test'
window.addEventListener('keydown', function(event) {
if (event.key === 't') {
document.getElementById('sg-9e275afocus-test').focus();
}
});
</script>
</div>
</div>
</div>
</div>
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-8ec9e5" type="button" class="vi-btn-solid vi-btn">Launch modal without data dismiss on the button</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-8ec9e5" role="dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout -->
<div class="vi-modal-layout">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<h3>Cornhole venmo loko.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="mb-20" style="height: calc(var(--vh) * 25)">
<!-- Scrollpane -->
<div class="vi-scrollpane">
<div class="vi-scrollpane__bar">
...
...
...
...
...
</div>
</div>
</div>
<div class="text-center">
<!-- Button type: solid -->
<button id="sg-8ec9e5focus-test" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Chambray aesthetic</button>
</div>
</div>
</div>
</div>
<script>
// Window on key t down, focus element with id 'focus-test'
window.addEventListener('keydown', function(event) {
if (event.key === 't') {
document.getElementById('sg-8ec9e5focus-test').focus();
}
});
</script>
</div>
</div>
</div>
</div>
When modals become too long for the user’s viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean.
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-576bd6" type="button" class="vi-btn-solid vi-btn">Launch demo modal</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-576bd6" role="dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal Layout -->
<div class="vi-modal-layout">
<div class="vi-modal-layout__body">
<div class="vi-modal-layout__section vi-modal-layout__section--header-close">
<div class="vi-modal-layout__header vi-typesystem vi-typesystem--collapse-last">
<h3>Hoodie park street.</h3>
</div>
<div class="vi-modal-layout__close">
<!-- Button type: close -->
<button aria-label="Message dialog - click to close or navigate to the message content" data-dismiss="modal" type="button" class="vi-btn-close vi-btn-close--accent-1 vi-btn"><span class="vi-btn-close__label vi-btn__label">Close</span></button>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="vi-typesystem">
<p>Pork belly poutine roof blog quinoa. Microdosing biodiesel chillwave pinterest deep v fashion axe pork belly taxidermy. Aesthetic venmo pork belly thundercats bespoke.</p>
<p>Pinterest tilde banh mi selfies truffaut iphone viral skateboard. Gentrify blog meditation vice fixie trust fund. Yolo austin portland muggle magic cred vice try-hard. Post-ironic everyday cray fingerstache put a bird on it.</p>
<p>Trust fund drinking offal pour-over meditation banjo quinoa. Poutine carry brooklyn gluten-free next level microdosing tofu shoreditch. Salvia cred butcher cleanse actually pinterest banh mi.</p>
<p>Carry iphone portland hoodie banjo sustainable. Kale chips park taxidermy keffiyeh master ugh sriracha. Chia godard kogi 8-bit.</p>
<p>Drinking authentic ramps. Park ugh master pug pour-over heirloom next level lumbersexual. Microdosing deep v mlkshk.</p>
<p>Skateboard vinegar retro you probably haven't heard of them flannel before they sold out. Single-origin coffee phlogiston kinfolk messenger bag vinyl. Locavore portland keffiyeh chillwave +1 cliche austin. Ugh trust fund cronut pinterest bushwick meditation artisan.</p>
<p>Roof raw denim direct trade carry mlkshk polaroid. Gluten-free fingerstache 3 wolf moon hella forage letterpress lomo raw denim. Meditation tacos pitchfork tilde biodiesel keffiyeh echo. Muggle magic gluten-free carry.</p>
<p>Authentic kitsch sriracha hella cardigan pabst fanny pack ramps. Muggle magic put a bird on it organic. Squid austin heirloom next level. Kinfolk meh tote bag. Lo-fi food truck yuccie pitchfork wayfarers.</p>
<p>Readymade green juice kickstarter lo-fi flannel leggings blog. Kogi plaid you probably haven't heard of them yr. Swag tattooed cold-pressed.</p>
<p>Cred xoxo seitan hammock swag raw denim. Fingerstache tacos helvetica disrupt shabby chic retro. Hashtag tattooed messenger bag. 90's pork belly sartorial leggings artisan keffiyeh. Lomo bitters truffaut craft beer schlitz.</p>
<p>+1 pickled disrupt next level everyday squid umami lo-fi. Cronut intelligentsia cleanse letterpress. Plaid wayfarers food truck freegan swag shoreditch messenger bag bicycle rights.</p>
<p>Trust fund leggings tofu hashtag. Viral church-key portland tousled williamsburg irony. Squid post-ironic truffaut narwhal gentrify. Banjo kinfolk cardigan shoreditch. Kale chips tousled bushwick tilde knausgaard poutine actually authentic.</p>
<p>Chambray letterpress pbr&b health cornhole. Irony typewriter shoreditch drinking freegan wes anderson health wayfarers. Chia gastropub cardigan cold-pressed yr helvetica. Bushwick kinfolk you probably haven't heard of them celiac. Brooklyn skateboard wolf letterpress squid.</p>
<p>Banh mi actually +1 salvia cleanse microdosing deep v kombucha. Hella viral locavore pabst wes anderson. Godard beard brunch waistcoat skateboard ugh flexitarian. Keytar semiotics try-hard. Typewriter bushwick master listicle gastropub beard.</p>
<p>Blue bottle yr phlogiston skateboard keytar swag portland. +1 everyday migas squid kickstarter sartorial mustache park. Dreamcatcher heirloom deep v master pork belly pitchfork etsy poutine. Chambray loko retro. Meditation messenger bag kickstarter.</p>
<p>Godard biodiesel distillery 8-bit. Slow-carb heirloom narwhal park. Carry mustache salvia venmo five dollar toast chambray.</p>
<p>Twee microdosing austin quinoa synth lo-fi. Tilde helvetica 90's godard ramps pickled. Migas yr keytar xoxo cornhole.</p>
</div>
<div class="text-center">
<!-- Button type: solid -->
<button data-dismiss="modal" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Fixie polaroid</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The following stylesheets are required to display this component.
The following javascripts are required to display this component.
Usage documentation can be found here.
Changelog
- 09 Oct 2025 - fix(modal): Focus next focusable element when no data-dismiss attr is present
- 09 Oct 2025 - docs(modal): Add focus button test on scrolling long content example.
Fix
- 25 Jan 2022 - Fix regression remove console.log output.
- 30 Nov 2022 - Fix regression caused by page-layout iOS overscroll prevention.
- 30 Sept 2022 - CSS class
.vi-modal-body-backdrop--black opaticy. (plus missing docs)
- Stop Video Component correctly when modal is closed.
- Original
.modal-sm and .modal-md options
Changed
- Layering (z-index) to not conflict with the Pop Navigation
- A11y Focus close button on open.
Added
- 23 Nov 2022 - Additional backdrop colors opaque and no blur.
- 22 Nov 2022 - Additional backdrop colors with PBS support.
- 14 Oct 2022 - Add
.modal-screen option for screen sized modal.
- 28 Sept 2022 - CSS class
.vi-modal-body-backdrop to add to the body of the page a page.
- Modifier
--black to have a black backdrop, as required by some regulations
- Example how to open the modal on page load.
- RTL support
- Initial draft