[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-popover-api-native-popovers":32,"code:js:true:z5inft":235,"code:html:true:1j43n9m":236,"code:js:true:f1lus6":237,"code:js:true:18d2kg0":238,"code:css:true:jkujbz":239},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":17,"paths":17,"articles":18,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":17},2,{"id":33,"slug":34,"title":35,"subtitle":36,"excerpt":37,"coverUrl":38,"locale":13,"readingMinutes":39,"publishedAt":40,"viewCount":41,"likeCount":19,"commentCount":19,"author":42,"vertical":47,"topic":48,"tags":51,"_count":63,"playground":65,"body":67,"bodyMd":218,"seo":219,"translationGroupId":222,"thread":223,"assessments":225,"translations":231,"quiz":233},"019fe660-1462-723e-9605-66ffa7e98f42","popover-api-native-popovers","Your dropdown is a div. The browser has a native popover now.",null,"Custom dropdowns, tooltips, and menus built with stacked divs and click-outside listeners — the Popover API landed in every browser in 2024, and the baseline version is two HTML attributes.","\u002Fmedia\u002Fcovers\u002Fpopover-api-native-popovers.png",4,"2026-07-12T08:24:42.323Z",11,{"id":43,"name":44,"username":45,"avatarUrl":36,"headline":46},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":49,"name":50},"javascript","JavaScript",[52,55,58,60],{"slug":53,"name":54,"color":36},"webdev","Webdev",{"slug":56,"name":57,"color":36},"frontend","Frontend",{"slug":49,"name":59,"color":36},"Javascript",{"slug":61,"name":62,"color":36},"css","Css",{"assessments":64},1,{"slug":34,"title":66},"The native Popover API — two attributes, no JS",{"blocks":68,"version":64},[69,73,79,82,85,89,92,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,146,149,152,156,159,162,166,169,172,175,179,182,185,188,191,194,197,200,203,206,209],{"id":70,"html":71,"type":72},"b1","\u003Cp>You&#39;ve written some version of this before:\u003C\u002Fp>","paragraph",{"id":74,"code":75,"type":76,"language":77,"highlight":78},"b2","function toggleMenu() {\n  setOpen(prev => !prev);\n}\n\nuseEffect(() => {\n  const handler = (e) => {\n    if (!ref.current?.contains(e.target)) setOpen(false);\n  };\n  document.addEventListener('mousedown', handler);\n  return () => document.removeEventListener('mousedown', handler);\n}, []);","code","js",[],{"id":80,"html":81,"type":72},"b3","\u003Cp>Plus the CSS that sets \u003Ccode>position: absolute; z-index: 9999\u003C\u002Fcode>. Plus the \u003Ccode>aria-expanded\u003C\u002Fcode> you forget half the time. Plus the Escape key handler you add after the first accessibility audit.\u003C\u002Fp>",{"id":83,"html":84,"type":72},"b4","\u003Cp>You&#39;ve been solving the same four problems — open\u002Fclose state, light dismiss, z-index, keyboard — over and over. They&#39;re browser problems. The browser fixed them.\u003C\u002Fp>",{"id":86,"html":87,"text":87,"type":88,"level":31},"b5","Two attributes","heading",{"id":90,"html":91,"type":72},"b6","\u003Cp>The Popover API is \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FPopover_API\">Baseline 2024\u003C\u002Fa>: shipping in Chrome 114, Firefox 125, and Safari 17. The baseline version looks like this:\u003C\u002Fp>",{"id":93,"code":94,"type":76,"language":95,"highlight":96},"b7","\u003Cbutton popovertarget=\"options-menu\">Options\u003C\u002Fbutton>\n\n\u003Cul id=\"options-menu\" popover>\n  \u003Cli>Edit\u003C\u002Fli>\n  \u003Cli>Duplicate\u003C\u002Fli>\n  \u003Cli>Delete\u003C\u002Fli>\n\u003C\u002Ful>","html",[],{"id":98,"html":99,"type":72},"b8","\u003Cp>That&#39;s the full implementation for the open\u002Fclose\u002Fdismiss problem. The browser wires \u003Ccode>popovertarget\u003C\u002Fcode> to the element with the matching \u003Ccode>id\u003C\u002Fcode>. Clicking the button opens the popover. Pressing Escape closes it. Clicking anywhere outside closes it. No JavaScript, no event listeners, no \u003Ccode>useRef\u003C\u002Fcode>.\u003C\u002Fp>",{"id":101,"html":102,"type":72},"b9","\u003C!-- playground:start -->",{"id":104,"html":105,"text":105,"type":88,"level":31},"b10","🎮 Try it yourself",{"id":107,"html":108,"type":72},"b11","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fposts\u002F2026-07-12-popover-api-native-popovers\u002Fplayground\u002F\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":110,"html":111,"type":72},"b12","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":113,"html":114,"type":72},"b13","\u003C!-- playground:end -->",{"id":116,"html":117,"type":72},"b14","\u003C!-- quiz:start -->",{"id":119,"html":120,"text":120,"type":88,"level":31},"b15","🧠 Test yourself",{"id":122,"html":123,"type":72},"b16","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fquiz\u002Ftake.html?post=2026-07-12-popover-api-native-popovers\">Take the 6-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":125,"html":126,"type":72},"b17","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":128,"html":129,"type":72},"b18","\u003C!-- quiz:end -->",{"id":131,"html":132,"text":132,"type":88,"level":31},"b19","The top layer is the real fix",{"id":134,"html":135,"type":72},"b20","\u003Cp>The reason your dropdown gets a \u003Ccode>z-index: 9999\u003C\u002Fcode> is because positioned elements compete inside stacking contexts, and anything with \u003Ccode>transform\u003C\u002Fcode>, \u003Ccode>opacity\u003C\u002Fcode>, or \u003Ccode>filter\u003C\u002Fcode> creates a new one that traps your menu below it. You can&#39;t escape a stacking context by going higher — you have to get \u003Cem>out\u003C\u002Fem> of it entirely.\u003C\u002Fp>",{"id":137,"html":138,"type":72},"b21","\u003Cp>Popovers render in the \u003Cstrong>top layer\u003C\u002Fstrong>: a browser-managed surface that sits above every stacking context in the document, including \u003Ccode>overflow: hidden\u003C\u002Fcode> parents and \u003Ccode>transform\u003C\u002Fcode>-ed ancestors. Your tooltip no longer disappears behind a sticky header. Your menu no longer clips inside a table cell. The top layer is outside the layout tree entirely — there&#39;s nowhere for it to get trapped.\u003C\u002Fp>",{"id":140,"html":141,"type":72},"b22","\u003Cp>\u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> modals use the same top layer. Popovers just make it available to any element, not just dialog elements.\u003C\u002Fp>",{"id":143,"html":144,"text":145,"type":88,"level":31},"b23","\u003Ccode>auto\u003C\u002Fcode> vs \u003Ccode>manual\u003C\u002Fcode>","auto vs manual",{"id":147,"html":148,"type":72},"b24","\u003Cp>\u003Ccode>popover\u003C\u002Fcode> (same as \u003Ccode>popover=&quot;auto&quot;\u003C\u002Fcode>) is the light-dismiss mode: only one auto popover is open at a time, clicking outside closes it, Escape closes it. This is what you want for menus and dropdowns.\u003C\u002Fp>",{"id":150,"html":151,"type":72},"b25","\u003Cp>\u003Ccode>popover=&quot;manual&quot;\u003C\u002Fcode> turns all that off. Nothing closes a manual popover unless your code explicitly does:\u003C\u002Fp>",{"id":153,"code":154,"type":76,"language":77,"highlight":155},"b26","const toast = document.getElementById('toast');\ntoast.showPopover();\n\nsetTimeout(() => toast.hidePopover(), 3000);",[],{"id":157,"html":158,"type":72},"b27","\u003Cp>Manual is right for toasts, alerts, and any UI where \u003Cem>you\u003C\u002Fem> decide when it goes away. Auto is right for anything the user should be able to dismiss by looking away from.\u003C\u002Fp>",{"id":160,"html":161,"type":72},"b28","\u003Cp>The JavaScript API rounds it out:\u003C\u002Fp>",{"id":163,"code":164,"type":76,"language":77,"highlight":165},"b29","el.showPopover();     \u002F\u002F open\nel.hidePopover();     \u002F\u002F close\nel.togglePopover();   \u002F\u002F flip state\n\nel.matches(':popover-open'); \u002F\u002F true when currently open",[],{"id":167,"html":168,"text":168,"type":88,"level":31},"b30","Adding enter and exit animations",{"id":170,"html":171,"type":72},"b31","\u003Cp>Popovers are \u003Ccode>display: none\u003C\u002Fcode> when closed. The browser switches them to \u003Ccode>display: block\u003C\u002Fcode> when open. That transition normally can&#39;t be animated — CSS can&#39;t interpolate between \u003Ccode>none\u003C\u002Fcode> and \u003Ccode>block\u003C\u002Fcode>.\u003C\u002Fp>",{"id":173,"html":174,"type":72},"b32","\u003Cp>Two features fix this. First, \u003Ccode>allow-discrete\u003C\u002Fcode> in the transition lets the browser animate through \u003Ccode>display\u003C\u002Fcode> changes. Second, \u003Ccode>@starting-style\u003C\u002Fcode> defines the animation&#39;s starting values for the moment the element first becomes visible:\u003C\u002Fp>",{"id":176,"code":177,"type":76,"language":61,"highlight":178},"b33","[popover] {\n  opacity: 0;\n  transform: translateY(-6px);\n  transition:\n    opacity 0.15s ease,\n    transform 0.15s ease,\n    display 0.15s allow-discrete;\n}\n\n[popover]:popover-open {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n@starting-style {\n  [popover]:popover-open {\n    opacity: 0;\n    transform: translateY(-6px);\n  }\n}",[],{"id":180,"html":181,"type":72},"b34","\u003Cp>The \u003Ccode>:popover-open\u003C\u002Fcode> block is the \u003Cem>target\u003C\u002Fem> state. \u003Ccode>@starting-style\u003C\u002Fcode> tells the browser where to start the animation from — without it, the element appears fully visible in frame one and your enter animation never plays. Exit animations (the element going back to hidden) happen in reverse across the same transition.\u003C\u002Fp>",{"id":183,"html":184,"text":184,"type":88,"level":31},"b35","What you still need a library for",{"id":186,"html":187,"type":72},"b36","\u003Cp>The Popover API handles the surface and the dismiss behavior. It doesn&#39;t handle positioning.\u003C\u002Fp>",{"id":189,"html":190,"type":72},"b37","\u003Cp>If your dropdown needs to flip above the trigger when there&#39;s no room below, or shift left when it would overflow the viewport edge, you&#39;ll still want \u003Ca href=\"https:\u002F\u002Ffloating-ui.com\u002F\">Floating UI\u003C\u002Fa> or a similar library — or the \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002FCSS_anchor_positioning\">CSS Anchor Positioning API\u003C\u002Fa>, which ties a floating element to an anchor element natively. Anchor positioning is shipping in Chrome and gaining traction, but isn&#39;t cross-browser yet.\u003C\u002Fp>",{"id":192,"html":193,"type":72},"b38","\u003Cp>It also doesn&#39;t give you a complete accessible menu pattern for free. Arrow-key navigation inside the list, \u003Ccode>role=&quot;menu&quot;\u003C\u002Fcode> \u002F \u003Ccode>role=&quot;menuitem&quot;\u003C\u002Fcode> ARIA semantics, and focus management within the options are still yours to implement — or delegate to a headless component library. What you get free: Escape key, light dismiss, top-layer placement, and the \u003Ccode>aria-expanded\u003C\u002Fcode> state (browsers update it automatically when the popover opens via \u003Ccode>popovertarget\u003C\u002Fcode>).\u003C\u002Fp>",{"id":195,"html":196,"text":196,"type":88,"level":31},"b39","The short version",{"id":198,"html":199,"type":72},"b40","\u003Cp>If you&#39;re building a dropdown, tooltip trigger, disclosure panel, or any floating UI today, start with the Popover API. Light dismiss, Escape key, and top-layer rendering come for free. Animations cost you a \u003Ccode>@starting-style\u003C\u002Fcode> block. Viewport-aware positioning still needs Floating UI or Anchor Positioning.\u003C\u002Fp>",{"id":201,"html":202,"type":72},"b41","\u003Cp>The click-outside listener you&#39;ve written a hundred times is a browser primitive now. Use the primitive.\u003C\u002Fp>",{"id":204,"type":205},"b42","divider",{"id":207,"html":208,"type":72},"b43","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":210,"type":211,"items":212,"ordered":18},"b44","list",[213,214,215,216,217],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","💼 \u003Cstrong>LinkedIn\u003C\u002Fstrong> — \u003Ca href=\"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F\">linkedin.com\u002Fin\u002Fparsa-jiravand\u003C\u002Fa>","✉️ \u003Cstrong>Email\u003C\u002Fstrong> (work &amp; contract inquiries): \u003Ca href=\"mailto:bestpractice2026@gmail.com\">bestpractice2026@gmail.com\u003C\u002Fa>","You've written some version of this before:\n\n```js\nfunction toggleMenu() {\n  setOpen(prev => !prev);\n}\n\nuseEffect(() => {\n  const handler = (e) => {\n    if (!ref.current?.contains(e.target)) setOpen(false);\n  };\n  document.addEventListener('mousedown', handler);\n  return () => document.removeEventListener('mousedown', handler);\n}, []);\n```\n\nPlus the CSS that sets `position: absolute; z-index: 9999`. Plus the `aria-expanded` you forget half the time. Plus the Escape key handler you add after the first accessibility audit.\n\nYou've been solving the same four problems — open\u002Fclose state, light dismiss, z-index, keyboard — over and over. They're browser problems. The browser fixed them.\n\n## Two attributes\n\nThe Popover API is [Baseline 2024](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FPopover_API): shipping in Chrome 114, Firefox 125, and Safari 17. The baseline version looks like this:\n\n```html\n\u003Cbutton popovertarget=\"options-menu\">Options\u003C\u002Fbutton>\n\n\u003Cul id=\"options-menu\" popover>\n  \u003Cli>Edit\u003C\u002Fli>\n  \u003Cli>Duplicate\u003C\u002Fli>\n  \u003Cli>Delete\u003C\u002Fli>\n\u003C\u002Ful>\n```\n\nThat's the full implementation for the open\u002Fclose\u002Fdismiss problem. The browser wires `popovertarget` to the element with the matching `id`. Clicking the button opens the popover. Pressing Escape closes it. Clicking anywhere outside closes it. No JavaScript, no event listeners, no `useRef`.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fposts\u002F2026-07-12-popover-api-native-popovers\u002Fplayground\u002F)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 6-question quiz →](https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fquiz\u002Ftake.html?post=2026-07-12-popover-api-native-popovers)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\n## The top layer is the real fix\n\nThe reason your dropdown gets a `z-index: 9999` is because positioned elements compete inside stacking contexts, and anything with `transform`, `opacity`, or `filter` creates a new one that traps your menu below it. You can't escape a stacking context by going higher — you have to get *out* of it entirely.\n\nPopovers render in the **top layer**: a browser-managed surface that sits above every stacking context in the document, including `overflow: hidden` parents and `transform`-ed ancestors. Your tooltip no longer disappears behind a sticky header. Your menu no longer clips inside a table cell. The top layer is outside the layout tree entirely — there's nowhere for it to get trapped.\n\n`\u003Cdialog>` modals use the same top layer. Popovers just make it available to any element, not just dialog elements.\n\n## `auto` vs `manual`\n\n`popover` (same as `popover=\"auto\"`) is the light-dismiss mode: only one auto popover is open at a time, clicking outside closes it, Escape closes it. This is what you want for menus and dropdowns.\n\n`popover=\"manual\"` turns all that off. Nothing closes a manual popover unless your code explicitly does:\n\n```js\nconst toast = document.getElementById('toast');\ntoast.showPopover();\n\nsetTimeout(() => toast.hidePopover(), 3000);\n```\n\nManual is right for toasts, alerts, and any UI where *you* decide when it goes away. Auto is right for anything the user should be able to dismiss by looking away from.\n\nThe JavaScript API rounds it out:\n\n```js\nel.showPopover();     \u002F\u002F open\nel.hidePopover();     \u002F\u002F close\nel.togglePopover();   \u002F\u002F flip state\n\nel.matches(':popover-open'); \u002F\u002F true when currently open\n```\n\n## Adding enter and exit animations\n\nPopovers are `display: none` when closed. The browser switches them to `display: block` when open. That transition normally can't be animated — CSS can't interpolate between `none` and `block`.\n\nTwo features fix this. First, `allow-discrete` in the transition lets the browser animate through `display` changes. Second, `@starting-style` defines the animation's starting values for the moment the element first becomes visible:\n\n```css\n[popover] {\n  opacity: 0;\n  transform: translateY(-6px);\n  transition:\n    opacity 0.15s ease,\n    transform 0.15s ease,\n    display 0.15s allow-discrete;\n}\n\n[popover]:popover-open {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n@starting-style {\n  [popover]:popover-open {\n    opacity: 0;\n    transform: translateY(-6px);\n  }\n}\n```\n\nThe `:popover-open` block is the *target* state. `@starting-style` tells the browser where to start the animation from — without it, the element appears fully visible in frame one and your enter animation never plays. Exit animations (the element going back to hidden) happen in reverse across the same transition.\n\n## What you still need a library for\n\nThe Popover API handles the surface and the dismiss behavior. It doesn't handle positioning.\n\nIf your dropdown needs to flip above the trigger when there's no room below, or shift left when it would overflow the viewport edge, you'll still want [Floating UI](https:\u002F\u002Ffloating-ui.com\u002F) or a similar library — or the [CSS Anchor Positioning API](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002FCSS_anchor_positioning), which ties a floating element to an anchor element natively. Anchor positioning is shipping in Chrome and gaining traction, but isn't cross-browser yet.\n\nIt also doesn't give you a complete accessible menu pattern for free. Arrow-key navigation inside the list, `role=\"menu\"` \u002F `role=\"menuitem\"` ARIA semantics, and focus management within the options are still yours to implement — or delegate to a headless component library. What you get free: Escape key, light dismiss, top-layer placement, and the `aria-expanded` state (browsers update it automatically when the popover opens via `popovertarget`).\n\n## The short version\n\nIf you're building a dropdown, tooltip trigger, disclosure panel, or any floating UI today, start with the Popover API. Light dismiss, Escape key, and top-layer rendering come for free. Animations cost you a `@starting-style` block. Viewport-aware positioning still needs Floating UI or Anchor Positioning.\n\nThe click-outside listener you've written a hundred times is a browser primitive now. Use the primitive.\n\n---\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)\n- 💼 **LinkedIn** — [linkedin.com\u002Fin\u002Fparsa-jiravand](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F)\n- ✉️ **Email** (work & contract inquiries): [bestpractice2026@gmail.com](mailto:bestpractice2026@gmail.com)",{"title":35,"canonical":220,"description":221},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fpopover-api-native-popovers","Custom dropdowns, tooltips, and menus built with stacked divs and click-outside listeners — the Popover API landed in every browser in 2024, and the baseline version is two HTML at","019fe660-1462-723e-9605-695b37e201e4",{"id":224,"locked":18},"019fe660-1b54-7152-b15a-8ec0d0b9e8b5",[226],{"id":227,"slug":34,"title":228,"_count":229},"019fe776-3af6-756b-9681-39d9647f7091","Native Popovers (Popover API)",{"questions":230},6,[232],{"locale":13,"slug":34},{"id":227,"slug":34,"title":228,"_count":234,"questionCount":230},{"questions":230},"\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003Cdiv>11\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan> \u003Cspan class=\"shj-func\">toggleMenu\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-func\">setOpen\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>prev \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-oper\">!\u003C\u002Fspan>prev\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-func\">useEffect\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> \u003Cspan class=\"shj-func\">handler\u003C\u002Fspan> \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>e\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">!\u003C\u002Fspan>ref\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>current\u003Cspan class=\"shj-oper\">?.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">contains\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>e\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>target\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-func\">setOpen\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bool\">false\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>;\n  document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'mousedown'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> handler\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">return\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">removeEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'mousedown'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> handler\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-html shj-multiline\" data-lang=\"html\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">button\u003C\u002Fspan> \u003Cspan class=\"shj-class\">popovertarget\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"options-menu\"\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Options\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">button\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">ul\u003C\u002Fspan> \u003Cspan class=\"shj-class\">id\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"options-menu\"\u003C\u002Fspan> \u003Cspan class=\"shj-class\">popover\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Edit\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Duplicate\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Delete\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">li\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">ul\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> toast \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">getElementById\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'toast'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\ntoast\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">showPopover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\n\u003Cspan class=\"shj-func\">setTimeout\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> toast\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">hidePopover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-num\">3000\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">el\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">showPopover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;     \u003Cspan class=\"shj-cmnt\">\u002F\u002F open\n\u003C\u002Fspan>el\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">hidePopover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;     \u003Cspan class=\"shj-cmnt\">\u002F\u002F close\n\u003C\u002Fspan>el\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">togglePopover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;   \u003Cspan class=\"shj-cmnt\">\u002F\u002F flip state\n\u003C\u002Fspan>\nel\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">matches\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">':popover-open'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>; \u003Cspan class=\"shj-cmnt\">\u002F\u002F true when currently open\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003Cdiv>11\u003C\u002Fdiv>\u003Cdiv>12\u003C\u002Fdiv>\u003Cdiv>13\u003C\u002Fdiv>\u003Cdiv>14\u003C\u002Fdiv>\u003Cdiv>15\u003C\u002Fdiv>\u003Cdiv>16\u003C\u002Fdiv>\u003Cdiv>17\u003C\u002Fdiv>\u003Cdiv>18\u003C\u002Fdiv>\u003Cdiv>19\u003C\u002Fdiv>\u003Cdiv>20\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">popover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">opacity\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">0\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">translateY\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>-\u003Cspan class=\"shj-num\">6\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">transition\u003C\u002Fspan>:\n    \u003Cspan class=\"shj-num\">opacity\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0.15\u003C\u002Fspan>s \u003Cspan class=\"shj-num\">ease\u003C\u002Fspan>,\n    \u003Cspan class=\"shj-num\">transform\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0.15\u003C\u002Fspan>s \u003Cspan class=\"shj-num\">ease\u003C\u002Fspan>,\n    \u003Cspan class=\"shj-num\">display\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0.15\u003C\u002Fspan>s \u003Cspan class=\"shj-num\">allow-discrete\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">popover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-var\">:popover-open\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">opacity\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">1\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">translateY\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">0\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">@starting\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">-style\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">popover\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-var\">:popover-open\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-var\">opacity\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">0\u003C\u002Fspan>;\n    \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">translateY\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>-\u003Cspan class=\"shj-num\">6\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>"]