{"id":2806,"date":"2024-06-24T13:54:13","date_gmt":"2024-06-24T19:54:13","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=2806"},"modified":"2024-06-24T13:54:14","modified_gmt":"2024-06-24T19:54:14","slug":"popovers-work-pretty-nicely-as-slide-out-drawers","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/popovers-work-pretty-nicely-as-slide-out-drawers\/","title":{"rendered":"Popovers Work Pretty Nicely as Slide-Out Drawers"},"content":{"rendered":"\n<p>I remain a little obsessed about the <code>popover<\/code> attribute. This innocuous little HTML attribute produces an accessible and design-friendly &#8220;popup&#8221; UI\/UX effect for little effort. I think the &#8220;tooltip&#8221; is generally the top use case for this feature, which is now <a href=\"https:\/\/caniuse.com\/mdn-api_htmlelement_popover\">well-supported<\/a> across the board. <\/p>\n\n\n\n<p>First, we looked at <a href=\"https:\/\/frontendmasters.com\/blog\/using-the-popover-api-for-html-tooltips\/\">how to use popovers for tooltips<\/a>. Because the anchor positioning API isn&#8217;t as well-supported yet, this leveraged JavaScript to do the positioning. <\/p>\n\n\n\n<p>Second, we looked at <a href=\"https:\/\/frontendmasters.com\/blog\/footnotes-progressively-enhanced-to-popovers\/\">progressively enhancing footnotes into tooltips<\/a>. This technique ultimately checked if the browser supported both popovers and anchor positioning and if so would do native popups, otherwise fallback to being a normal footnote, which is perfectly fine. <\/p>\n\n\n\n<p>This time, we&#8217;ll look at a tooltip design that <em>just doesn&#8217;t require<\/em> the anchor positioning API or any JavaScript positioning at all. We&#8217;ll make the tooltips slide out from the bottom of the screen instead.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"885\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/CleanShot-2024-06-24-at-14.24.04%402x.png?resize=1024%2C885&#038;ssl=1\" alt=\"example of a popover opening as a drawer\" class=\"wp-image-2813\" style=\"width:415px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/CleanShot-2024-06-24-at-14.24.04%402x.png?resize=1024%2C885&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/CleanShot-2024-06-24-at-14.24.04%402x.png?resize=300%2C259&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/CleanShot-2024-06-24-at-14.24.04%402x.png?resize=768%2C663&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/CleanShot-2024-06-24-at-14.24.04%402x.png?w=1102&amp;ssl=1 1102w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n<\/div>\n\n\n<p>I guess I&#8217;ll have to admit this is a series:<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/using-the-popover-api-for-html-tooltips\/\">Using the Popover API for HTML Tooltips<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/footnotes-progressively-enhanced-to-popovers\/\">Footnotes Progressively Enhanced to Popovers<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/popovers-work-pretty-nicely-as-slide-out-drawers\/\">Popovers Work Pretty Nicely as Slide-Out Drawers<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Closed = Footnote; Open = Drawer<\/h2>\n\n\n\n<p>This idea of drawer-based popups don&#8217;t require this fancy dance of having the content already visible on the page as a footnote. I just really like <a href=\"https:\/\/css-irl.info\/progressively-enhanced-popover-toggletips\/\">the idea<\/a>. In CSS, the ultimately expresses itself like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/* Display as a footnote *\/<\/span>\n&#91;popover] {\n  display: <span class=\"hljs-keyword\">list<\/span>-item;\n  ...\n\n  <span class=\"hljs-comment\">\/* Display as a drawer *\/<\/span>\n  &amp;:popover-open {\n    position: fixed;\n    ...\n\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will ultimately require a bunch of declarations to force the content into both shapes. Such is CSS. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Progressive Enhancement Happens at the Link\/Button Level<\/h2>\n\n\n\n<p>Footnotes, the &#8220;fallback&#8221; for this, require an <code>&lt;a&gt;<\/code> link to jump down to them. Whereas the popups require a <code>&lt;button&gt;<\/code> to work. So we actually need to display both right next to each other:<\/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\">a<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"footnote-anchor\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#ref_1\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">sup<\/span>&gt;<\/span>1<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">sup<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">popovertarget<\/span>=<span class=\"hljs-string\">\"ref_1\"<\/span>&gt;<\/span>1<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/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>You could do this either-way-around, but here we&#8217;ll hide the anchor links by default and only show them if popups aren&#8217;t supported:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.footnote-anchor<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: none;\n}\n<span class=\"hljs-selector-tag\">html<\/span><span class=\"hljs-selector-class\">.no-popovers<\/span> {\n  .footnote-anchor {\n    <span class=\"hljs-attribute\">display<\/span>: inline;\n  }\n  <span class=\"hljs-selector-attr\">&#91;popovertarget]<\/span> {\n    <span class=\"hljs-attribute\">display<\/span>: none;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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>We have this <code>no-popovers<\/code> class via:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">if<\/span> (!HTMLElement.prototype.hasOwnProperty(<span class=\"hljs-string\">\"popover\"<\/span>)) {\n  <span class=\"hljs-built_in\">document<\/span>.documentElement.classList.add(<span class=\"hljs-string\">\"no-popovers\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">The Sliding Door<\/h2>\n\n\n\n<p>The trick to a drawer sliding out from the bottom of the screen is:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Fixed positioning of the drawer<\/li>\n\n\n\n<li>Translated off the page the height of itself<\/li>\n\n\n\n<li>Translated on to the page when opened<\/li>\n<\/ol>\n\n\n\n<p>That largely looks like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table\"><span class='shcb-loc'><span>&#91;popover] {\n<\/span><\/span><span class='shcb-loc'><span>  ...\n<\/span><\/span><span class='shcb-loc'><span>  \n<\/span><\/span><span class='shcb-loc'><span>  &amp;:popover-open {\n<\/span><\/span><span class='shcb-loc'><span>    z-index: <span class=\"hljs-number\">1<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    position: fixed;\n<\/span><\/span><span class='shcb-loc'><span>    inset: auto;\n<\/span><\/span><span class='shcb-loc'><span>    bottom: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    left: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    margin: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    width: <span class=\"hljs-number\">100<\/span>vi;\n<\/span><\/span><span class='shcb-loc'><span>    padding: <span class=\"hljs-number\">2<\/span>rem;\n<\/span><\/span><span class='shcb-loc'><span>    background: lavender;\n<\/span><\/span><span class='shcb-loc'><span>    box-shadow: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">-1<\/span>rem <span class=\"hljs-number\">5<\/span>rem oklch(<span class=\"hljs-number\">0<\/span>% <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> \/ <span class=\"hljs-number\">0.33<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><mark class='shcb-loc'><span>    animation: slide-open <span class=\"hljs-number\">0.2<\/span>s;\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* Make sure the popup isn't screen-covering *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    max-block-size: <span class=\"hljs-number\">50<\/span>dvh;\n<\/span><\/span><span class='shcb-loc'><span>    overflow: auto;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I was thinking we could pull off the slide-in of the drawer using <code>@starting-style<\/code> and a transition, but it turns out you can set the starting style of just the open state like we&#8217;d need here. Fortunately, we can just call a simple keyframe animation to do the trick:<\/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-keyword\">@keyframes<\/span> slide-open {\n  0% {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">translate<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">100%<\/span>);\n  }\n  100% {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">translate<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>);\n  }\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<h2 class=\"wp-block-heading\">Especially nice on mobile, but looks good on desktop too.<\/h2>\n\n\n\n<p>The drawer just seems to make sense on the mobile screen. I don&#8217;t think positioning the popup next to the button would even be that helpful, the drawer is nicer.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player aligncenter wp-block-jetpack-videopress--has-max-width\" style=\"max-width: 338px;\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='482' height='750' src='https:\/\/videopress.com\/embed\/OxLzI4FE?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=1674852142'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>But even on a larger screen it&#8217;s still fairly nice. We can take a little extra care to looslely center things a little <code>text-wrap: balance;<\/code> doesn&#8217;t hurt.<\/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='337' src='https:\/\/videopress.com\/embed\/v5NqrgvG?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=1674852142'><\/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\">Demo<\/h2>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_VwOXBPZ\" src=\"\/\/codepen.io\/anon\/embed\/VwOXBPZ?height=450&amp;theme-id=47434&amp;slug-hash=VwOXBPZ&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed VwOXBPZ\" title=\"CodePen Embed VwOXBPZ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/using-the-popover-api-for-html-tooltips\/\">Using the Popover API for HTML Tooltips<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/footnotes-progressively-enhanced-to-popovers\/\">Footnotes Progressively Enhanced to Popovers<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/popovers-work-pretty-nicely-as-slide-out-drawers\/\">Popovers Work Pretty Nicely as Slide-Out Drawers<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Especially on mobile, the slide-out drawer UI\/UX seems like a perfect fit for a popover, and works fine on desktop too. <\/p>\n","protected":false},"author":1,"featured_media":1975,"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,31,190],"class_list":["post-2806","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-html","tag-popup"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/popup-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2806","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=2806"}],"version-history":[{"count":11,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2806\/revisions"}],"predecessor-version":[{"id":2824,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2806\/revisions\/2824"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/1975"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=2806"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=2806"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=2806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}