{"id":4069,"date":"2024-09-30T11:38:20","date_gmt":"2024-09-30T16:38:20","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=4069"},"modified":"2024-09-30T11:38:21","modified_gmt":"2024-09-30T16:38:21","slug":"whats-the-difference-between-htmls-dialog-element-and-popovers","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/whats-the-difference-between-htmls-dialog-element-and-popovers\/","title":{"rendered":"What&#8217;s the Difference Between HTML&#8217;s Dialog Element and Popovers?"},"content":{"rendered":"\n<p>They are different HTML, to begin with. A dialog is like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dialog<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"my-dialog\"<\/span>&gt;<\/span>\n  Content\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dialog<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>While a popover is an attribute on some other element:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">aside<\/span> <span class=\"hljs-attr\">popover<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"my-popover\"<\/span>&gt;<\/span>\n  Content\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">aside<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The reason it&#8217;s worth comparing them is that they are quite similar in a lot of ways, both in look and functionality, which can be confusing. It&#8217;s worth thinking about which one you really need.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">They are both hidden-by-default<\/h2>\n\n\n\n<p>If you put either bit of the HTML above onto the page, they will be visually hidden as well as ignored in the accessibility tree by default (but available in the DOM). It isn&#8217;t until you specifically show them (via JavaScript or on-page HTML control when available) that they are visible.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"762\" height=\"248\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.32.24%E2%80%AFAM.png?resize=762%2C248&#038;ssl=1\" alt=\"\" class=\"wp-image-4098\" style=\"width:431px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.32.24%E2%80%AFAM.png?w=762&amp;ssl=1 762w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.32.24%E2%80%AFAM.png?resize=300%2C98&amp;ssl=1 300w\" sizes=\"auto, (max-width: 762px) 100vw, 762px\" \/><figcaption class=\"wp-element-caption\">Accessibility tree with a hidden dialog and popover in it.<\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"346\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.33.48%E2%80%AFAM.png?resize=1024%2C346&#038;ssl=1\" alt=\"\" class=\"wp-image-4099\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.33.48%E2%80%AFAM.png?resize=1024%2C346&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.33.48%E2%80%AFAM.png?resize=300%2C101&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.33.48%E2%80%AFAM.png?resize=768%2C259&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-11.33.48%E2%80%AFAM.png?w=1138&amp;ssl=1 1138w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">When dialog is open, it&#8217;s a part of the accessibility tree.<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>You <em>can<\/em> make a <code>&lt;dialog&gt;<\/code> visible by default in HTML alone:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dialog<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"my-dialog\"<\/span><\/span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">open<\/span><\/span>\n<\/span><\/mark><span class='shcb-loc'><span><span class=\"hljs-tag\">&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  Content\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dialog<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Where you <em>cannot<\/em> make a popover visible in HTML alone. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Popovers Have HTML-Only Controls<\/h2>\n\n\n\n<p>You <em>can<\/em> make a popover work (open &amp; close) with HTML controls alone:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-comment\">&lt;!-- This button will open and close the matching popover. No JavaScript required. --&gt;<\/span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">popovertarget<\/span>=<span class=\"hljs-string\">\"my-popover\"<\/span>&gt;<\/span>\n<\/span><\/mark><span class='shcb-loc'><span>  Toggle Popover\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">aside<\/span> <span class=\"hljs-attr\">popover<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"my-popover\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  Content of popover\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">aside<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>But you <em>cannot<\/em> build HTML-only controls for a <code>&lt;dialog&gt;<\/code>. Opening and closing a dialog requires JavaScript event handlers. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">JavaScript APIs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Dialog JavaScript APIs<\/h3>\n\n\n\n<p>The dialog APIs in JavaScript are interesting in that there are two different distinct APIs for opening it. This is where the term &#8220;modal&#8221; comes in. Modal is sometimes used as a term for the UI element itself, but here it essentially means if the modal should trap focus inside of it while open, or not. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>.show()<\/code> \u2014 Open the dialog in a <strong>non-modal<em> <\/em><\/strong>state, meaning no backdrop is shown and no focus trapping happens. Note that using the <code>open<\/code> attribute in the HTML\/DOM to open the dialog is the same (non-modal).  <\/li>\n\n\n\n<li><code>.showModal()<\/code> \u2014 Open the dialog in a <strong>modal<em> <\/em><\/strong>meaning a backdrop is shown and focus is trapped within the modal. <\/li>\n\n\n\n<li><code>.close()<\/code> \u2014 Closes the dialog (if it&#8217;s open). <\/li>\n<\/ul>\n\n\n\n<p>The <code>showModal()<\/code> method can throw if the dialog is already open in a non-modal state. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Uncaught InvalidStateError: Failed to execute 'showModal' on 'HTMLDialogElement': The dialog is already open as a non-modal dialog, and therefore cannot be opened as a modal dialog.<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Popover JS APIs<\/h3>\n\n\n\n<p>Popovers also have JavaScript APIs, but both the opening and closing APIs are different than with modals and do not overlap. These are pretty self explanatory. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>.showPopover()<\/code> \u2014 Opens the popover.<\/li>\n\n\n\n<li><code>.hidePopover()<\/code> \u2014 Closes the popover.<\/li>\n<\/ul>\n\n\n\n<p>Calling <code>showPopover<\/code> on an already open popover or <code>hidePopover<\/code> on an already hidden popover does not throw. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Focus Trapping<\/h2>\n\n\n\n<p>The ability of the dialog element to be opened in a modal state and thus trap focus inside of it is a superpower of this element. It is unique to the dialog element, popovers cannot do this (on their own).<\/p>\n\n\n\n<p>Focus trapping, while it sounds kinda bad, is actually an accessibility <em>feature.<\/em> After all, that&#8217;s what a modal is: it <em>forces you to deal with some interaction<\/em> before anything else can be done. It&#8217;s actually <em>also<\/em> a <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/no-keyboard-trap.html\">WCAG requirement to <em>not<\/em> trap focus<\/a> when you shouldn&#8217;t, but in the case of a modal, you <em>should<\/em> be trapping focus \u2014 as well as providing a standard way to close the dialog and escape the trap.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='253' src='https:\/\/videopress.com\/embed\/44BRNALa?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1725245713'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>Focus can change to other focusable elements inside, and when you&#8217;re about to move focus forward to the next element when you&#8217;re at the last, it circles back to the first focusable element within the dialog. <strong>You get all this &#8220;for free&#8221; with a <code>&lt;dialog&gt;<\/code> opened with <code>showModal()<\/code><\/strong>, which is otherwise a huge pain in the ass and you probably won&#8217;t even do it right (sorry). <\/p>\n\n\n\n<p>If you need this focus trapping, don&#8217;t use a popover as it&#8217;s not for this job. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Moving Focus<\/h2>\n\n\n\n<p>When a dialog is opened (either modal or non-modal), <strong>focus is moved to the first focusable element within it<\/strong>. When it is closed, focus is moved back to the element that opened it.<\/p>\n\n\n\n<p>With a popover, focus remains on the element that opened it even after the popup is opened. However, after the popup is open, the next tab will put focus into the popup&#8217;s content if there is any in there, regardless of where it is in the DOM, tab through the focusable elements of the popup, then onto other focusable elements outside the popup after the original element that opened it. <\/p>\n\n\n\n<p>This is all tricky work that you get for free by using the <code>&lt;dialog&gt;<\/code> element or popups and frankly a huge reason to use them \ud83d\udc4d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Escape Key<\/h2>\n\n\n\n<p>Both <em>modal<\/em> dialogs and popups, when open, <strong>can be closed by pressing the ESC key. <\/strong>Very handy behavior that helps adhere to accessibility adherence, again given for free, which is tricky and error-prone to write yourself.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='322' src='https:\/\/videopress.com\/embed\/yRithh5s?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1725245713'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>Non-modal dialogs do not close with the ESC key, so you&#8217;ll need to provide your own close functionality, like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onclick<\/span>=<span class=\"hljs-string\">\"myDialog.close()\"<\/span>&gt;<\/span>Close<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">They Have the Same Default Styling<\/h2>\n\n\n\n<p>Dialogs and popovers look the same by default and have really basic default styling that you&#8217;ll almost certainly want to override. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"776\" height=\"408\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.28.22%E2%80%AFAM.png?resize=776%2C408&#038;ssl=1\" alt=\"\" class=\"wp-image-4088\" style=\"width:482px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.28.22%E2%80%AFAM.png?w=776&amp;ssl=1 776w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.28.22%E2%80%AFAM.png?resize=300%2C158&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.28.22%E2%80%AFAM.png?resize=768%2C404&amp;ssl=1 768w\" sizes=\"auto, (max-width: 776px) 100vw, 776px\" \/><\/figure>\n<\/div>\n\n\n<p>They are essentially <code>position: fixed;<\/code> and <code>margin: auto;<\/code> which centers them in the viewport. This is a probably a smart default for dialogs. In my opinion, popovers are usually begging for <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_anchor_positioning\">anchor positioning<\/a> to open the popover near where the element that opened it is, but they <a href=\"https:\/\/frontendmasters.com\/blog\/popovers-work-pretty-nicely-as-slide-out-drawers\/\">work nicely as slide-out drawers<\/a> as well, particularly on mobile. <\/p>\n\n\n\n<p>You&#8217;ll likely want to bring your own padding, border, background, typography, internal structure, etc. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Top Layer<\/h2>\n\n\n\n<p>Another amazing feature of both dialogs and popovers is that, when open, they are placed on what is called the &#8220;top layer&#8221;. It is literally impossible for any other element to be on top of them. It doesn&#8217;t matter where they are in the DOM (could be quite nested) or what containing blocks or <code>z-index<\/code> is involved, the top layer is the top no matter what. (Although \u2013 it is true that if you open <em>subsequent dialogs\/popovers<\/em>, e.g. a button in a dialog opens another dialog, the second one will beat the first and be on top, as you&#8217;d expect.) This top-layer ability is yet another thing you get for free and a fantastic reason to use these native features.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"255\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/CleanShot-2024-09-30-at-11.35.04%402x.png?resize=1024%2C255&#038;ssl=1\" alt=\"\" class=\"wp-image-4101\" style=\"width:564px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/CleanShot-2024-09-30-at-11.35.04%402x.png?resize=1024%2C255&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/CleanShot-2024-09-30-at-11.35.04%402x.png?resize=300%2C75&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/CleanShot-2024-09-30-at-11.35.04%402x.png?resize=768%2C191&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/CleanShot-2024-09-30-at-11.35.04%402x.png?w=1206&amp;ssl=1 1206w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">DevTools showing the #top-layer<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Backdrops<\/h2>\n\n\n\n<p>Both (modal) dialogs and popovers use (and share) a backdrop. This is the layer above all content on the page that covers the page (by default), but is still underneath the actual dialog or popover. This backdrop is a very light transparent black by default, but can be styled like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-pseudo\">::backdrop<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">color-mix<\/span>(in srgb, purple, transparent <span class=\"hljs-number\">20%<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That will apply <em>both<\/em> to modal dialogs and default popovers. If you wanted to have different backdrops for them, you could scope them like this, as the backdrop is applied to the element that is open:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-attr\">&#91;popover]<\/span><span class=\"hljs-selector-pseudo\">::backdrop<\/span> {\n  \n}\n\n<span class=\"hljs-selector-tag\">dialog<\/span><span class=\"hljs-selector-pseudo\">::backdrop<\/span> {\n  \n}\n\n<span class=\"hljs-selector-class\">.some-very-specific-element<\/span><span class=\"hljs-selector-pseudo\">::backdrop<\/span> {\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"890\" height=\"342\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.31.04%E2%80%AFAM.png?resize=890%2C342&#038;ssl=1\" alt=\"\" class=\"wp-image-4089\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.31.04%E2%80%AFAM.png?w=890&amp;ssl=1 890w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.31.04%E2%80%AFAM.png?resize=300%2C115&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.31.04%E2%80%AFAM.png?resize=768%2C295&amp;ssl=1 768w\" sizes=\"auto, (max-width: 890px) 100vw, 890px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"826\" height=\"392\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.30.56%E2%80%AFAM.png?resize=826%2C392&#038;ssl=1\" alt=\"\" class=\"wp-image-4090\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.30.56%E2%80%AFAM.png?w=826&amp;ssl=1 826w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.30.56%E2%80%AFAM.png?resize=300%2C142&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-30-at-10.30.56%E2%80%AFAM.png?resize=768%2C364&amp;ssl=1 768w\" sizes=\"auto, (max-width: 826px) 100vw, 826px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>You don&#8217;t <em>have<\/em> to show a backdrop if you don&#8217;t want to, but it&#8217;s a good indicator for users particularly when modal behavior is in play (and perhaps an anti-pattern when it&#8217;s not, as you may be visually hiding elements in focus). <\/p>\n\n\n\n<p>Non-modal dialogs do not have a backdrop. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Soft Dismiss<\/h2>\n\n\n\n<p>This feature is unique to popovers. You can &#8220;click outside&#8221; the popover to close it, by default (yet another tricky behavior to code yourself). I&#8217;ve used the term &#8220;default popover&#8221; in this article and what I mean is when you don&#8217;t provide a value to the <code>popover<\/code> attribute. That implies <code>auto<\/code> as a value which is what makes soft dismissal work. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-comment\">&lt;!-- Soft Dismissible --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">popover<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"myPopover\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-comment\">&lt;!-- Soft Dismissible --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">popover<\/span>=<span class=\"hljs-string\">\"auto\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"myPopover\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-comment\">&lt;!-- NOT Soft Dismissible --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">popover<\/span>=<span class=\"hljs-string\">\"manual\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"myPopover\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='238' src='https:\/\/videopress.com\/embed\/ie5AYi9v?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1725245713'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<h2 class=\"wp-block-heading\">Multiple Open<\/h2>\n\n\n\n<p>Both dialogs and popovers can have multiple open at once. The most recent one to be opened will be the one that is most &#8220;on top&#8221; and will close the first via soft dismiss or the ESC key. (Also <a href=\"https:\/\/frontendmasters.com\/blog\/closewatcher\/\">see the CloseWatcher API<\/a>). <\/p>\n\n\n\n<p>For a modal dialog, note that because the rest of the page is essentially <code>inert<\/code> when it is open, the near-only way to open another is via interactivity within the first opened dialog.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='256' src='https:\/\/videopress.com\/embed\/fJIk3img?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1725245713'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>For popups, because the default behavior has soft dismissal, the popovers will need to be <code>popover=\"manual\"<\/code> or be opened with JavaScript without interaction for multiple of them to be open. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Purpose and Semantics<\/h2>\n\n\n\n<p>Popovers likely have more use cases than dialogs. Any time you <a href=\"https:\/\/frontendmasters.com\/blog\/using-the-popover-api-for-html-tooltips\/\">need a tooltip<\/a> or to provide more contextual information that has good reason not to be visible by default, a popover is a good choice.<\/p>\n\n\n\n<p>Non modal dialogs are pretty similar to a popup, but are perhaps better suited to situations where there is no other element on the page that is relevant to the messaging. Perhaps something like a &#8220;No internet connection detected&#8221; message, which could be very important to tell a user, but doesn&#8217;t need to 100% stop other activity on the page. <\/p>\n\n\n\n<p>Modal dialogs are show-stoppers, forcing a user to deal with them before anything else can happen. They should be used sparingly (they are reached for <a href=\"https:\/\/modalzmodalzmodalz.com\/\">far too much<\/a>, some people say). Perhaps a message like &#8220;Are you sure you want to delete this entire document? This cannot be undone.&#8221; would be a modal dialog, as any other interaction on the page is moot should the user be deleting.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Animation<\/h2>\n\n\n\n<p>This is all very cutting edge right now, so browser support is spotty, but both of these elements <a href=\"https:\/\/frontendmasters.com\/blog\/the-dialog-element-with-entry-and-exit-animations\/\">can be animated both on the way in and out<\/a>. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><a href=\"https:\/\/codepen.io\/chriscoyier\/pen\/NWQGjRv\">I played around with this Pen<\/a> while I was thinking and working on all this, which may be helpful to you if you&#8217;re doing the same. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>They are pretty similar in both look and functionality, but are have some important differences, slightly different APIs, and functionality. The use cases are also a bit different, so let&#8217;s have a look! <\/p>\n","protected":false},"author":1,"featured_media":4097,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7,98,31,120],"class_list":["post-4069","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-dialog","tag-html","tag-popover"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/modal.jpg?fit=1162%2C530&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4069","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=4069"}],"version-history":[{"count":18,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4069\/revisions"}],"predecessor-version":[{"id":4103,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4069\/revisions\/4103"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/4097"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=4069"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=4069"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=4069"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}