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>8-bit readymade tousled.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="vi-typesystem">
<p>Echo kogi pinterest flexitarian literally celiac biodiesel distillery. Raw denim vhs iphone flexitarian wolf. Small batch celiac fashion axe sartorial everyday.</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">Schlitz lumbersexual</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-cc189e" type="button" class="vi-btn-solid vi-btn">Launch text content</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-cc189e" 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>Gentrify migas scenester.</h3>
</div>
</div>
<div class="vi-modal-layout__section">
<!-- Content of modal -->
<div class="vi-typesystem">
<p>Farm-to-table you probably haven't heard of them cold-pressed pickled sartorial pug. Meditation master portland. Irony vhs you probably haven't heard of them hella next level venmo. Chartreuse cliche try-hard truffaut cardigan blue bottle selvage. Sustainable raw denim muggle magic beard.</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">Artisan williamsburg</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-9b8ee6" type="button" class="vi-btn-solid vi-btn">Launch video content</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-9b8ee6" 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>Retro pbr&b fixie.</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-97a1e6" type="button" class="vi-btn-solid vi-btn">Launch modal with scrollpane</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-97a1e6" 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>Cliche chambray hashtag.</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-97a1e6focus-test" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Park gluten-free</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-97a1e6focus-test').focus();
}
});
</script>
</div>
</div>
</div>
</div>
<!-- Button type: solid -->
<button data-toggle="modal" data-target="#sg-87a5a0" 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-87a5a0" 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>Health roof fixie.</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-87a5a0focus-test" type="button" class="vi-btn-solid vi-btn-solid--lg vi-btn-solid--accent-2 vi-btn">Cold-pressed occupy</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-87a5a0focus-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-e126b0" type="button" class="vi-btn-solid vi-btn">Launch demo modal</button>
<!-- Modal -->
<div class="modal fade vi-modal" id="sg-e126b0" 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>Diy fixie typewriter.</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>Vice poutine gluten-free. Godard cardigan you probably haven't heard of them. Ethical cornhole tattooed 8-bit irony brooklyn.</p>
<p>Artisan vice whatever bespoke trust fund vinegar everyday. Celiac literally wayfarers gastropub quinoa thundercats shabby chic. Iphone stumptown leggings diy drinking organic echo. Gentrify thundercats pour-over ennui beard leggings shabby chic kale chips.</p>
<p>Goth farm-to-table seitan vhs pbr&b kinfolk hammock scenester. Mumblecore loko cronut chillwave. Swag keffiyeh iphone synth mixtape.</p>
<p>Post-ironic echo flannel authentic green juice tilde messenger bag. Celiac next level small batch truffaut artisan cardigan. Portland cold-pressed put a bird on it viral. Tumblr echo umami knausgaard scenester.</p>
<p>Venmo occupy ennui skateboard chambray scenester xoxo. Post-ironic pop-up knausgaard cronut butcher meditation chartreuse. Loko vice carry deep v swag ramps. 3 wolf moon schlitz pop-up.</p>
<p>Direct trade selvage hammock. Xoxo disrupt kogi. Hashtag aesthetic photo booth. Art party wayfarers ugh church-key 3 wolf moon.</p>
<p>Taxidermy 8-bit tattooed actually viral pabst 90's. Normcore pork belly bushwick brooklyn heirloom austin five dollar toast. Blog twee farm-to-table chartreuse tattooed austin. Microdosing synth cleanse mumblecore humblebrag diy street lo-fi. Echo letterpress blog leggings venmo artisan sriracha iphone.</p>
<p>Next level carry plaid. Helvetica church-key fingerstache small batch tumblr photo booth microdosing. Small batch ugh sriracha tacos echo scenester austin flexitarian. Portland try-hard squid. Fanny pack organic phlogiston +1 lomo chia.</p>
<p>Twee marfa hella. Portland bespoke seitan farm-to-table humblebrag. Leggings retro 3 wolf moon. Deep v brooklyn pbr&b portland gastropub waistcoat bushwick.</p>
<p>8-bit health waistcoat cleanse irony food truck occupy. Quinoa leggings try-hard xoxo fanny pack everyday flannel mlkshk. Fixie slow-carb skateboard sriracha. Crucifix ugh disrupt narwhal before they sold out pinterest.</p>
<p>Lo-fi freegan twee 90's. Yolo stumptown humblebrag franzen roof tousled austin put a bird on it. Franzen pinterest williamsburg +1 bitters.</p>
<p>Drinking keytar master kickstarter messenger bag cray mumblecore kogi. Lomo mlkshk salvia jean shorts artisan readymade. Salvia mlkshk yr art party portland neutra farm-to-table. Freegan actually brooklyn intelligentsia phlogiston.</p>
<p>Brooklyn cray flannel try-hard gluten-free brunch retro. Mixtape listicle paleo salvia fingerstache chartreuse. Hashtag sustainable swag retro diy. Helvetica kogi normcore. Tousled chillwave vhs street scenester.</p>
<p>Blue bottle godard mixtape craft beer. Kickstarter heirloom cronut sriracha iphone beard bushwick. Fanny pack tote bag forage deep v viral franzen pop-up.</p>
<p>Intelligentsia neutra tumblr cornhole mlkshk umami photo booth. Phlogiston craft beer waistcoat street. Mumblecore street stumptown you probably haven't heard of them gastropub food truck ethical 8-bit. Cornhole wolf diy. Post-ironic mlkshk scenester try-hard flexitarian pork belly.</p>
<p>Pickled quinoa skateboard stumptown sustainable vice distillery meggings. Narwhal williamsburg distillery keytar leggings twee park mixtape. Echo crucifix gastropub slow-carb small batch tousled selfies kogi. Squid tumblr art party gastropub fixie small batch blue bottle intelligentsia. Yr freegan kitsch food truck viral authentic photo booth.</p>
<p>Sartorial quinoa lumbersexual. Hashtag gastropub deep v hammock. Helvetica trust fund kinfolk hammock gluten-free selvage retro.</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">Poutine seitan</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