{"id":79701,"date":"2018-07-11T13:22:40","date_gmt":"2018-07-11T13:22:40","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=79701"},"modified":"2022-05-02T20:48:26","modified_gmt":"2022-05-02T20:48:26","slug":"using-modal-dialog-boxes-in-bootstrap-4","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/javascript\/using-modal-dialog-boxes-in-bootstrap-4\/","title":{"rendered":"Using Modal Dialog Boxes in Bootstrap 4"},"content":{"rendered":"<p>Let\u2019s start from the very beginning. What does \u2018modal dialog\u2019 mean actually? A modal dialog is a window (sometimes just referred to as a \u2018box\u2019) that forces the user to interact. In other words, a modal dialog box has the precise purpose of interrupting the ongoing workflow until its content is reviewed or interacted with. There are many cases in which a modal dialog is helpful\u2014for example, when you wish to get confirmation from the user about the operation just being started. A modal dialog box is often used to show optional information about an item being displayed on screen or to let users perform optional operations. A common example is the following.<\/p>\n<p>Suppose you are going to add a booking in the name of a user that doesn\u2019t exist yet in the system. The operator is in the <strong>add-booking<\/strong> workflow but needs to take a diversion and temporarily switch to the add-user workflow. Once finished, she needs to go back to the original workflow. In a web scenario, without a modal dialog box, the entire flow is fairly convoluted as the operator needs to navigate to a different page, post its content, and then find a link to return back where she was. It\u2019s clearly doable, but sometimes we developers love shortcuts and users love shortcuts too.<\/p>\n<p>This is just a common use-case where modal dialog boxes may, or may not, be really helpful. It all depends on the details of the flow being interrupted and the diversion flow to inject. It all depends also on the amount of information being interacted in the diversion flow. Finally, there are users that love modals and users who just hate them because they\u2019re too intrusive. There are no certain rules and facts about modals and this is enough to raise a flag whenever their use is considered or advocated during development. If I have to summarize my personal position about modals, it would be: if it\u2019s not simple and short then it can&#8217;t go into a modal. A second rule I apply to modals is: if the content is read-only and doesn\u2019t require a strict acknowledgement from the user, then consider using a <strong>drop-down<\/strong> element instead.<\/p>\n<p>In any version of Bootstrap, drop-down elements are not limited to menus, though the documentation up until version 3.x seems to suggest just that. In Bootstrap 4, instead, there\u2019s plenty of documentation on how to use drop-down classes to display just any content that can fit into a DIV container. Having said that, let\u2019s just see what it takes to create a modal dialog box in Bootstrap 4.<\/p>\n<h2>How to Create Modal Dialogs in Bootstrap 4<\/h2>\n<p>Modal dialog boxes have been made a lot more configurable in Bootstrap 4 but the core HTML layout and the programming model around it has not changed much. Here\u2019s the core HTML template you need.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0class=\"modal\"\u00a0id=\"modalDialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-dialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-content\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-header\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h5\u00a0class=\"modal-title\"&gt;What\u00a0are\u00a0we\u00a0doing\u00a0here&lt;\/h5&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button\u00a0type=\"button\"\u00a0class=\"close\"\u00a0data-dismiss=\"modal\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span&gt;&amp;times;&lt;\/span&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-body\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;p&gt;Content\u00a0of\u00a0the\u00a0modal\u00a0window&lt;\/p&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-footer\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button\u00a0type=\"button\"\u00a0class=\"btn\u00a0btn-primary\"&gt;Done&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button\u00a0type=\"button\"\u00a0class=\"btn\u00a0btn-secondary\"\u00a0\r\n                        data-dismiss=\"modal\"&gt;Close&lt;\/button&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>It\u2019s not different from previous versions of Bootstrap, but a quick look at its main characteristics is in order. A modal window is fully contained in a DIV element styled as <strong>modal<\/strong>. The ID of this element is the ID of the entire modal window. The outermost container incorporates another DIV layer styled as <strong>modal-dialog<\/strong> which in turn includes another DIV container styled as <strong>modal-content<\/strong>. This is the actual repository of the content presented to the user. The modal-content DIV is articulated in three parts each styled with a different Bootstrap class: <strong>modal-header<\/strong>, <strong>modal-body<\/strong> and <strong>modal-footer<\/strong>.<\/p>\n<p>Any areas of the modal window can contain anything that is HTML compliant. However, some conventions apply. For example, the header typically contains the title of the dialog that Bootstrap styles through the <strong>modal-title<\/strong> class. The footer conventionally contains the list of buttons to finalize the interaction between the user and the content. The <strong>data-dismiss<\/strong> custom attribute marks those buttons and links that cause the dialog to close after click.<\/p>\n<p>A Bootstrap modal dialog box is initially hidden and pops up when some ad hoc JavaScript code is invoked.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;script&gt;\r\n\u00a0\u00a0\u00a0\u00a0$('#modalDialog').modal('show')\r\n&lt;\/script&gt;<\/pre>\n<p>Most of the time, you don\u2019t write that JavaScript code yourself but just have it silently run when the user clicks a launcher button or link. A launcher element is any HTML element that reacts to any DOM events with the above code or that is decorated with the attributes <strong>data-toggle<\/strong> and <strong>data-target<\/strong>, as below.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0data-toggle=\"modal\"\u00a0data-target=\"#modalDialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0Touch\u00a0me <a id=\"post-79701-gjdgxs\"><\/a>to open the modal window\r\n&lt;\/div&gt;<\/pre>\n<p>Most commonly, however, the launcher is a button or a link. The launcher also supports the <strong>data-backdrop<\/strong> attribute which impacts the dismissal process of the dialog box. By default, the attribute is set to <strong>true<\/strong> meaning that the modal appears on top of a dark overlay (as if the underlying content is grayed out) and clicking outside the dialog automatically dismisses it. If you change the value to <strong>static<\/strong> then the dark overlay remains but to dismiss the dialog users must explicitly click on buttons. Finally, the value of <strong>false<\/strong> doesn\u2019t gray out the underlying content but still requires button clicking to dismiss the dialog. The <strong>data-keyboard<\/strong> attribute instead controls what happens when the ESC key is pressed. By default (value of <strong>true<\/strong>) the dialog is dismissed. With a value of <strong>false<\/strong>, pressing the ESC key has no effect.<\/p>\n<h2>Improvements in Bootstrap 4<\/h2>\n<p>Modal dialogs are plain artifacts of HTML, CSS, and JavaScript placed on top of everything else in the page. Intelligently, a modal dialog hooks up scrolling events so that if the content to show is too long for the vertical screen real estate the dialog scrolls instead of the browser window. This happens by design in Bootstrap 4 and requires no additional code or markup than what showed earlier. Be aware that when dealing with dialogs Bootstrap sets the <strong>position<\/strong> CSS element to a value of <strong>fixed<\/strong>. It is recommended that you avoid mixing up Bootstrap modals with other elements in the same page styled with a fixed position.<\/p>\n<p>The use of fixed positioning is problematic on some mobile devices too because of the way that some mobile browsers on some OS versions implement it. The Bootstrap web site contains plenty of known facts in this regard. To ensure you\u2019re on the safe side anyway, though, I do recommend you don\u2019t use modal dialogs on mobile devices. As for desktop browsers, it is worth noting that Bootstrap 4 <strong>does not<\/strong> support versions of Internet Explorer earlier than 10.<\/p>\n<p>By default, the dialog box appears near the top of the available screen and horizontally centered. However, at the cost of adding the <strong>modal-dialog-centered<\/strong> class to the <strong>modal-dialog<\/strong> container, you can have it displayed right at the center of the screen centered both vertically and horizontally.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0class=\"modal\"\u00a0id=\"modalDialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-dialog modal-dialog-centered\"&gt;\r\n      ...\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>Note that this feature doesn\u2019t work on Internet Explorer, even in the latest version 11.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-79702\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-63.png\" width=\"540\" height=\"640\" \/><\/p>\n<p>The content of the modal dialog can use Bootstrap\u2019s grids as well as more sophisticated elements such as tooltips and popovers. In Bootstrap 4, though, it is guaranteed that tooltips and popovers that might be visible are automatically dismissed as the dialog is dismissed. If you use grids to lay out the content of the dialog box, then it is advisable that you opt for the <strong>container-fluid<\/strong> class rather than <strong>container<\/strong>. The difference is that the class <strong>container<\/strong> has one fixed width for each supported screen size whereas <strong>container-fluid<\/strong> expands to fill the available width. The <strong>container-fluid<\/strong> style therefore ensures a better and more uniform placement of elements in the available space.<\/p>\n<p>The width of the modal dialog is calculated internally but you can influence it by adding the <strong>modal-lg<\/strong> or <strong>modal-sm<\/strong> classes to the modal-content container, as shown below.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0class=\"modal\"\u00a0id=\"modalDialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-dialog modal-lg\"&gt;\r\n      ...\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>Note that if you set modal-lg then the size is automatically adapted as the browser is resized to a smaller viewport.<\/p>\n<p>As mentioned, the content of the dialog is articulated in three nested DIV layers. What if you add some content outside those layers? If you add DIV elements within the modal-content container but outside header, body and footer you just achieve the effect of adding separators, as shown below.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-79703\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-64.png\" width=\"497\" height=\"556\" \/><\/p>\n<p>Even more interesting, if you place a DIV element before the modal-content container then the content appears outside the dialog producing a nice tab effect, as in the figure below.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0class=\"modal\"\u00a0id=\"modalDialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-dialog\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"bg-success\"&gt;BEFORE\u00a0CONTENT&lt;\/div&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"modal-content\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"bg-success\"&gt;BEFORE\u00a0HEADER&lt;\/div&gt;\r\n         ...\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-79704\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-65.png\" width=\"605\" height=\"563\" \/><\/p>\n<h2>Initializing a Dialog Box<\/h2>\n<p>Most of the time a modal dialog box is only a template to be filled with information that depends on the context. As an example, imagine the scenario in which you use a modal dialog to edit the profile of the currently logged user. Your HTML template will likely contain a form but actual values are to be provided on the fly. You can customize the content of the modal dialog by intercepting the <strong>show.bs.modal<\/strong> event. The event is fired as soon as the show method on the modal is invoked, whether programmatically or as the effect of clicking a launcher button. All the changes you apply to the template are performed before the modal is displayed. The <strong>shown.bs.modal<\/strong> event, instead, is fired right after the modal is turned on in the screen. An analogous pair of events exist for when the dialog box is hidden. Events are <strong>hide.bs.modal<\/strong> and <strong>hidden.bs.modal<\/strong>.<\/p>\n<p>As an example of the other approach, let\u2019s consider another common use-case: playing a YouTube video. In this case, the HTML template of the dialog may look like below:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;div\u00a0id=\"ytModal\"\u00a0class=\"modal\u00a0fade\"&gt;\r\n...\r\n&lt;div\u00a0class=\"modal-header\"&gt;\r\n   &lt;h5\u00a0class=\"modal-title\"&gt;All\u00a0for\u00a0a\u00a0block\u00a0in\u00a0the\u00a0chain&lt;\/h5&gt;\r\n   &lt;button\u00a0type=\"button\"\u00a0class=\"close\"\u00a0data-dismiss=\"modal\"&gt;\u00d7&lt;\/button&gt;\r\n&lt;\/div&gt;\r\n&lt;div\u00a0class=\"modal-body\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;div\u00a0class=\"text-center\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;iframe\u00a0height=\"315\"\u00a0width=\"560\"\u00a0frameborder=\"0\"\u00a0\r\n                allow=\"autoplay;\u00a0encrypted-media\"\u00a0\r\n                allowfullscreen&gt;\r\n        &lt;\/iframe&gt;\r\n\u00a0\u00a0\u00a0\u00a0&lt;\/div&gt;\r\n&lt;\/div&gt;\r\n...\r\n&lt;\/div&gt;<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-79705\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-66.png\" width=\"676\" height=\"366\" \/><\/p>\n<p>The IFRAME is preconfigured with the default parameters of YouTube shared videos. You can obtain those parameters by simply clicking the button Share in the YouTube page of the video and selecting the tab for embedding the video in a HTML page.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">&lt;script&gt;\r\n\u00a0\u00a0\u00a0\u00a0$(\"#ytModal\").on(\"show.bs.modal\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0function(e)\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var\u00a0src\u00a0=\u00a0\"https:\/\/www.youtube.com\/embed\/uaYfD6_xX30\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$(\"#ytModal\u00a0iframe\").attr(\"src\",\u00a0src);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\u00a0\u00a0\u00a0\u00a0\r\n&lt;\/script&gt;<\/pre>\n<p>The full source code is on <a href=\"https:\/\/bit.ly\/2znGhVP\">Github<\/a>.<\/p>\n<p>In the specific scenario of playing a video I anyway prefer opting for a dedicated jQuery plugin rather than a handmade Bootstrap modal dialog as the plugin would automatically handle the resize of the element to fit the video size. My favorite modal video plugin can be found <a href=\"https:\/\/appleple.github.io\/modal-video\">here<\/a>.<\/p>\n<h2>A Brief UX Analysis of Modal Dialogs<\/h2>\n<p>As mentioned, modal dialogs are a bit controversial and should be used only with the full approval of the client. In any case, though, there are a few guidelines to keep in mind as far as user experience is concerned.<\/p>\n<p>First and foremost, it should always be obvious for users how to escape the dialog. It can be done in a number of ways, for example through a button in the header. This is probably the most common and expected way of doing it. Another relatively familiar way of dismissing a dialog is by hitting the ESC key. As mentioned, support for the ESC key is enabled by default but can be disabled through the <strong>data-keyboard<\/strong> attribute on the launcher button. The keyboard-based way of dismissing the dialog should never be disabled though as it represents a powerful tool to keep accessibility higher.<\/p>\n<p>As far as clicking outside the element to dismiss it, that\u2019s enabled by default but sometimes it can be confusing for users, especially inexpert users. You might want to consider using a static backdrop and add perhaps a second bigger button in the footer to escape the dialog without performing any action.<\/p>\n<p>Bootstrap doesn\u2019t support nested modals and nested modals, however, should not be planned even using alternate plugins and frameworks. I prefer to always make my modals large and have them resize as the viewport reduces. At any rate, you should always keep the content to a minimum and avoid richly populated dialogs with complex and sophisticated forms.<\/p>\n<p>Finally, bear in mind that modal dialogs and mobile devices usually don\u2019t go that well together. The primary reason is screen space. If the content includes input fields then you should also consider the space needed for the device keyboard and possibly the internal scrollbar. As a result of a poorly displaying modal, users might be left zooming, scrolling and panning the screen in order to enter the input they\u2019re expected to enter. In general, unless you have a proven way to lay out elements in such a way the whole dialog displays nicely on small mobile devices, you should just look up for alternatives. The issue is that alternatives for mobile devices lead to reconsidering the entire workflow for example redirecting users to distinct pages for each content that would go on a modal. If this is too complicated, some middle ground can be using full-screen containers ad hoc for mobile sizes of the viewport. There\u2019s no easy way out and the old saying \u201cit depends\u201d is truer than ever.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bootstrap provides an easy way to add modal dialogs to web pages. Dino Esposito explains how to create modal dialogs with Bootstrap and describes the improvements available with Bootstrap 4. &hellip;<\/p>\n","protected":false},"author":221911,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[146044],"tags":[95509],"coauthors":[6780],"class_list":["post-79701","post","type-post","status-publish","format-standard","hentry","category-javascript","tag-standardize"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221911"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=79701"}],"version-history":[{"count":11,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79701\/revisions"}],"predecessor-version":[{"id":79707,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79701\/revisions\/79707"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=79701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=79701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=79701"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=79701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}