[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"playground-popover-api-native-popovers":32},[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,{"slug":33,"title":34,"summary":35,"html":36,"css":37,"js":38,"config":39,"doc":41},"popover-api-native-popovers","The native Popover API — two attributes, no JS",null,"\u003Cdiv class=\"wrap\">\n    \u003Ch1>🎮 Two attributes, a real popover\u003C\u002Fh1>\n    \u003Cp class=\"sub\">\n      The card below is a \u003Cstrong>native popover\u003C\u002Fstrong> — wired with just\n      \u003Ccode>&lt;button popovertarget&gt;\u003C\u002Fcode> + \u003Ccode>popover=\"auto\"\u003C\u002Fcode>. No JavaScript for\n      open\u002Fclose, click-outside dismiss, Escape, or z-index. The log shows the browser's own\n      \u003Ccode>toggle\u003C\u002Fcode> events. Everything you touch here is the real feature.\n    \u003C\u002Fp>\n\n    \u003Cdiv class=\"note\" id=\"unsupported\" hidden>\n      ⚠️ Your browser doesn't support the \u003Cstrong>Popover API\u003C\u002Fstrong> yet, so the live demo is hidden.\n      It's Baseline 2024 — try a recent Chrome, Edge, Safari, or Firefox to poke it. The\n      before\u002Fafter code below still tells the story.\n    \u003C\u002Fdiv>\n\n    \u003C!-- LIVE DEMO ------------------------------------------------------->\n    \u003Cdiv class=\"panel live\">\n      \u003Ch2>1 · Open it, then dismiss it three ways\u003C\u002Fh2>\n      \u003Cp class=\"cap\">\n        Click \u003Cstrong>Open settings\u003C\u002Fstrong>. Then close it however you like: click the button\n        again, \u003Cstrong>click anywhere outside\u003C\u002Fstrong>, or press \u003Cstrong>Esc\u003C\u002Fstrong>. Watch the log\n        in panel 3 name each event.\n      \u003C\u002Fp>\n      \u003Cdiv class=\"controls\">\n        \u003Cbutton id=\"open-btn\" class=\"open-btn\" popovertarget=\"settings-pop\">⚙&nbsp; Open settings\u003C\u002Fbutton>\n        \u003Cbutton id=\"reset\" class=\"ghost\">Reset demo\u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n\n      \u003C!-- The real native popover. In the top layer, so its DOM position here\n           doesn't matter — it renders above everything. -->\n      \u003Cdiv id=\"settings-pop\" popover=\"auto\">\n        \u003Cp class=\"pop-title\">Settings\u003C\u002Fp>\n        \u003Cp class=\"pop-note\">A plain \u003Ccode class=\"inline\">&lt;div popover&gt;\u003C\u002Fcode> in the top layer — above every stacking context.\u003C\u002Fp>\n        \u003Cdiv class=\"setting\">\u003Cspan>Dark mode\u003C\u002Fspan>\u003Cinput type=\"checkbox\" checked aria-label=\"Dark mode\" \u002F>\u003C\u002Fdiv>\n        \u003Cdiv class=\"setting\">\u003Cspan>Email notifications\u003C\u002Fspan>\u003Cinput type=\"checkbox\" aria-label=\"Email notifications\" \u002F>\u003C\u002Fdiv>\n        \u003Cdiv class=\"setting\">\u003Cspan>Compact rows\u003C\u002Fspan>\u003Cinput type=\"checkbox\" checked aria-label=\"Compact rows\" \u002F>\u003C\u002Fdiv>\n        \u003Cdiv class=\"pop-actions\">\n          \u003C!-- Opens a SECOND popover from inside this one: top-layer stacking, no z-index. -->\n          \u003Cbutton class=\"ghost\" popovertarget=\"confirm-pop\">Reset defaults…\u003C\u002Fbutton>\n          \u003C!-- Explicit close — the only thing that dismisses a manual popover. -->\n          \u003Cbutton popovertarget=\"settings-pop\" popovertargetaction=\"hide\">Close\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n      \u003C!-- Nested popover, opened from within the one above. Always auto. -->\n      \u003Cdiv id=\"confirm-pop\" popover=\"auto\">\n        \u003Cp class=\"pop-title\">Reset to defaults?\u003C\u002Fp>\n        \u003Cp class=\"pop-note\">This popover opened from inside the other one — both stack in the top layer, and there isn't a single \u003Ccode class=\"inline\">z-index\u003C\u002Fcode> in this demo.\u003C\u002Fp>\n        \u003Cdiv class=\"pop-actions\">\n          \u003Cbutton popovertarget=\"confirm-pop\" popovertargetaction=\"hide\">Confirm\u003C\u002Fbutton>\n          \u003Cbutton class=\"ghost\" popovertarget=\"confirm-pop\" popovertargetaction=\"hide\">Cancel\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- CONTROLS -------------------------------------------------------->\n    \u003Cdiv class=\"panel live\">\n      \u003Ch2>2 · Feel the two knobs\u003C\u002Fh2>\n      \u003Cdiv class=\"row\">\n        \u003Cspan class=\"lbl\">Dismiss mode\u003C\u002Fspan>\n        \u003Cdiv class=\"seg\" role=\"group\" aria-label=\"Dismiss mode\">\n          \u003Cbutton data-mode=\"auto\" aria-pressed=\"true\">auto\u003C\u002Fbutton>\n          \u003Cbutton data-mode=\"manual\" aria-pressed=\"false\">manual\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cp class=\"cap\" id=\"mode-hint\">auto: click outside or press Esc to dismiss, and only one auto popover is open at a time.\u003C\u002Fp>\n      \u003Cdiv class=\"row\">\n        \u003Cspan class=\"lbl\">Entrance\u003C\u002Fspan>\n        \u003Clabel>\u003Cinput type=\"checkbox\" id=\"anim-chk\" checked \u002F> Animate with \u003Ccode class=\"inline\">@starting-style\u003C\u002Fcode>\u003C\u002Flabel>\n      \u003C\u002Fdiv>\n      \u003Cp class=\"cap\">Off = the popover snaps in instantly. On = it fades and slides — the whole animation is one \u003Ccode class=\"inline\">@starting-style\u003C\u002Fcode> block, no keyframes. Reopen the popover after toggling to see the difference.\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003C!-- EVENT LOG ------------------------------------------------------->\n    \u003Cdiv class=\"panel live\">\n      \u003Ch2>3 · The browser is doing the work\u003C\u002Fh2>\n      \u003Cdiv class=\"status\">\n        \u003Cspan>\u003Cspan class=\"k\">state:\u003C\u002Fspan> \u003Cspan class=\"val off\" id=\"st-state\">CLOSED\u003C\u002Fspan>\u003C\u002Fspan>\n        \u003Cspan>\u003Cspan class=\"k\">popover=\u003C\u002Fspan> \u003Cspan class=\"val mode\" id=\"st-mode\">auto\u003C\u002Fspan>\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n      \u003Cul class=\"log\" id=\"log\" aria-live=\"polite\">\u003C\u002Ful>\n      \u003Cp class=\"cap\" style=\"margin-top:12px\">Each line is a native \u003Ccode class=\"inline\">toggle\u003C\u002Fcode> event — the same event you'd listen to in real code. You wrote none of the dismiss logic.\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003C!-- BEFORE \u002F AFTER -------------------------------------------------->\n    \u003Cdiv class=\"panel\">\n      \u003Ch2>4 · What you used to write vs. now\u003C\u002Fh2>\n      \u003Cdiv class=\"pair\">\n        \u003Cdiv class=\"side\">\n          \u003Cspan class=\"tag old\">the old way\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>\u003Cspan class=\"c\">\u002F\u002F state + a click-outside listener\u003C\u002Fspan>\n\u003Cspan class=\"k2\">const\u003C\u002Fspan> [open, setOpen] = useState(false);\nuseEffect(() => {\n  \u003Cspan class=\"k2\">const\u003C\u002Fspan> h = (e) =&gt; {\n    \u003Cspan class=\"k2\">if\u003C\u002Fspan> (!ref.current\u003Cspan class=\"a\">?\u003C\u002Fspan>.contains(e.target))\n      setOpen(false);\n  };\n  document.addEventListener(\u003Cspan class=\"v\">'mousedown'\u003C\u002Fspan>, h);\n  \u003Cspan class=\"k2\">return\u003C\u002Fspan> () =&gt; document\n    .removeEventListener(\u003Cspan class=\"v\">'mousedown'\u003C\u002Fspan>, h);\n}, []);\n\u003Cspan class=\"c\">\u002F* + Escape handler + aria-expanded\n   + position:absolute; \u003Cspan class=\"a\">z-index:9999\u003C\u002Fspan> *\u002F\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"side\">\n          \u003Cspan class=\"tag now\">now\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>\u003Cspan class=\"k2\">&lt;button\u003C\u002Fspan> \u003Cspan class=\"v\">popovertarget\u003C\u002Fspan>=\u003Cspan class=\"v\">\"menu\"\u003C\u002Fspan>\u003Cspan class=\"k2\">&gt;\u003C\u002Fspan>\n  Options\n\u003Cspan class=\"k2\">&lt;\u002Fbutton&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"k2\">&lt;div\u003C\u002Fspan> \u003Cspan class=\"v\">id\u003C\u002Fspan>=\u003Cspan class=\"v\">\"menu\"\u003C\u002Fspan> \u003Cspan class=\"v\">popover\u003C\u002Fspan>\u003Cspan class=\"k2\">&gt;\u003C\u002Fspan>\n  …\n\u003Cspan class=\"k2\">&lt;\u002Fdiv&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"c\">\u002F\u002F open\u002Fclose, click-outside,\n\u002F\u002F Escape, top layer, aria-expanded\n\u002F\u002F — all free. Zero JavaScript.\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cp class=\"foot\">\n      Baseline 2024 (Chrome 114, Firefox 125, Safari 17). What the API doesn't do: viewport-aware\n      \u003Cem>positioning\u003C\u002Fem> — this card just uses the browser's default centering. For dropdowns that flip\n      and shift you still reach for Floating UI or CSS Anchor Positioning.\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>",":root {\n    --bg: #0d1117; --panel: #161b22; --ink: #e8ebf2; --muted: #9aa4b2;\n    --accent: #7c9cff; --good: #3fb950; --bad: #f0883e; --line: #232a35;\n    font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n  }\n  * { box-sizing: border-box; }\n  body { margin: 0; background: var(--bg); color: var(--ink); min-height: 100vh;\n    display: flex; align-items: flex-start; justify-content: center; padding: 18px; }\n  .wrap { width: 100%; max-width: 680px; }\n  h1 { font-size: 1.2rem; margin: 0 0 3px; letter-spacing: -0.01em; }\n  .sub { color: var(--muted); font-size: .9rem; margin: 0 0 14px; line-height: 1.45; }\n  .sub code, code.inline { color: var(--accent); background: #ffffff10; padding: 1px 5px; border-radius: 5px;\n    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85em; }\n\n  .panel { background: var(--panel); border: 1px solid var(--line);\n    border-radius: 14px; padding: 16px; margin-bottom: 14px; }\n  .panel h2 { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em;\n    color: var(--muted); margin: 0 0 4px; font-weight: 700; }\n  .cap { color: var(--muted); font-size: .82rem; line-height: 1.45; margin: 0 0 12px; }\n  .cap:last-child { margin-bottom: 0; }\n\n  .controls { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }\n  button { font: inherit; font-weight: 600; color: #0b0d10; background: var(--accent);\n    border: 0; border-radius: 10px; padding: 10px 18px; cursor: pointer; }\n  button.ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); }\n  button:focus-visible, input:focus-visible, [popover] button:focus-visible {\n    outline: 2px solid var(--accent); outline-offset: 2px; }\n  .open-btn { font-size: 1rem; }\n\n  label { color: var(--muted); font-size: .82rem; display: inline-flex; gap: 8px; align-items: center; }\n  input[type=checkbox] { accent-color: var(--accent); width: 16px; height: 16px; }\n\n  \u002F* segmented auto\u002Fmanual toggle *\u002F\n  .seg { display: inline-flex; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }\n  .seg button { background: transparent; color: var(--muted); border: 0; border-radius: 0;\n    padding: 8px 14px; font-weight: 700; font-size: .82rem; }\n  .seg button[aria-pressed=\"true\"] { background: var(--accent); color: #0b0d10; }\n\n  .row { display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; margin-bottom: 10px; }\n  .row:last-of-type { margin-bottom: 0; }\n  .row .lbl { font-size: .8rem; color: var(--muted); min-width: 92px; }\n\n  \u002F* ---- the native popover card ---- *\u002F\n  [popover] {\n    margin: auto;                       \u002F* UA default: centered in the viewport *\u002F\n    inset: 0;\n    background: var(--panel); color: var(--ink);\n    border: 1px solid var(--line); border-radius: 14px;\n    padding: 18px; width: min(320px, calc(100vw - 34px));\n    box-shadow: 0 24px 70px #000000a0;\n  }\n  [popover]::backdrop { background: #05070c66; }\n  .pop-title { font-weight: 700; font-size: .95rem; margin: 0 0 4px; }\n  .pop-note { color: var(--muted); font-size: .78rem; margin: 0 0 14px; line-height: 1.4; }\n  .setting { display: flex; align-items: center; justify-content: space-between;\n    padding: 9px 0; border-top: 1px solid var(--line); font-size: .85rem; }\n  .setting:first-of-type { border-top: 0; }\n  .pop-actions { display: flex; gap: 8px; margin-top: 14px; }\n  .pop-actions button { flex: 1; padding: 9px 10px; }\n  #confirm-pop { width: min(280px, calc(100vw - 34px)); }\n  #confirm-pop .pop-title { color: var(--bad); }\n\n  \u002F* ---- entrance animation, gated behind body.anim so it can be A\u002FB'd ---- *\u002F\n  body.anim [popover] {\n    opacity: 0; transform: translateY(-10px) scale(.97);\n    transition: opacity .2s ease, transform .2s ease,\n                overlay .2s allow-discrete, display .2s allow-discrete;\n  }\n  body.anim [popover]:popover-open { opacity: 1; transform: none; }\n  @starting-style {\n    body.anim [popover]:popover-open { opacity: 0; transform: translateY(-10px) scale(.97); }\n  }\n\n  \u002F* ---- event log ---- *\u002F\n  .status { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 12px; font-size: .82rem; }\n  .status .k { color: var(--muted); }\n  .status .val { font-weight: 800; letter-spacing: .04em; }\n  .val.on { color: var(--good); } .val.off { color: var(--muted); } .val.mode { color: var(--accent); }\n  ul.log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px;\n    max-height: 190px; overflow-y: auto; }\n  ul.log:empty::after { content: \"No events yet — open the popover above.\"; color: var(--muted);\n    font-size: .8rem; font-style: italic; }\n  .ev { display: flex; align-items: baseline; gap: 9px; font-size: .82rem; padding: 7px 10px;\n    background: #0b0e14; border: 1px solid var(--line); border-radius: 9px; line-height: 1.35; }\n  .ev .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--muted); translate: 0 -1px; }\n  .ev.open .dot { background: var(--good); } .ev.close .dot { background: var(--bad); }\n  .ev.info .dot { background: var(--accent); }\n  .ev b { color: var(--ink); } .ev .det { color: var(--muted); }\n\n  \u002F* ---- before\u002Fafter code ---- *\u002F\n  .pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n  .side { border: 1px solid var(--line); border-radius: 11px; padding: 12px; background: #0b0e14; }\n  .tag { font-size: .7rem; font-weight: 700; letter-spacing: .04em; margin-bottom: 8px;\n    display: inline-block; padding: 3px 9px; border-radius: 999px; }\n  .tag.old { color: var(--bad); background: #f0883e1a; }\n  .tag.now { color: var(--good); background: #3fb9501a; }\n  pre { margin: 0; overflow-x: auto; font-size: .74rem; line-height: 1.55; }\n  pre code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n  .k2 { color: var(--accent); } .c { color: #6b7688; } .v { color: var(--good); } .a { color: var(--bad); }\n\n  .note { font-size: .82rem; color: var(--muted); background: #f0883e14;\n    border: 1px solid #f0883e40; border-radius: 10px; padding: 11px 13px; margin-bottom: 14px; line-height: 1.45; }\n  .note[hidden] { display: none; }\n  .foot { font-size: .78rem; color: var(--muted); line-height: 1.45; }\n  .foot code { color: var(--accent); }\n\n  @media (max-width: 470px) {\n    .pair { grid-template-columns: 1fr; }\n  }","const $ = (id) => document.getElementById(id);\n\n  \u002F\u002F Feature-detect: the property reflects the popover attribute only where the API exists.\n  const supported = HTMLElement.prototype.hasOwnProperty(\"popover\");\n  if (!supported) {\n    $(\"unsupported\").hidden = false;\n    document.querySelectorAll(\".panel.live\").forEach((el) => (el.style.display = \"none\"));\n  }\n\n  const pop = $(\"settings-pop\");\n  const confirmPop = $(\"confirm-pop\");\n  const trigger = $(\"open-btn\");\n  const logEl = $(\"log\");\n  const stState = $(\"st-state\");\n  const stMode = $(\"st-mode\");\n  const modeHint = $(\"mode-hint\");\n  const animChk = $(\"anim-chk\");\n\n  \u002F\u002F Why did the popover just close? Set synchronously by the input event that\n  \u002F\u002F caused it; read by the async `toggle` handler, then cleared.\n  let pendingReason = null;\n  const isAuto = () => pop.getAttribute(\"popover\") === \"auto\";\n\n  function log(verb, detail, kind) {\n    const li = document.createElement(\"li\");\n    li.className = \"ev \" + (kind || \"\");\n    li.innerHTML = '\u003Cspan class=\"dot\">\u003C\u002Fspan>\u003Cb>\u003C\u002Fb>&nbsp;\u003Cspan class=\"det\">\u003C\u002Fspan>';\n    li.querySelector(\"b\").textContent = verb;\n    li.querySelector(\".det\").textContent = detail;\n    logEl.prepend(li);\n    while (logEl.children.length > 8) logEl.lastElementChild.remove();\n  }\n\n  function updateStatus() {\n    const open = pop.matches(\":popover-open\");\n    stState.textContent = open ? \"OPEN\" : \"CLOSED\";\n    stState.className = \"val \" + (open ? \"on\" : \"off\");\n    stMode.textContent = pop.getAttribute(\"popover\");\n  }\n\n  \u002F\u002F The native toggle event — fires on every open\u002Fclose, no matter what caused it.\n  pop.addEventListener(\"toggle\", (e) => {\n    if (e.newState === \"open\") {\n      log(\"opened\", \"the browser placed it in the top layer\", \"open\");\n    } else {\n      log(\"closed\", pendingReason || \"hidePopover() was called\", \"close\");\n    }\n    pendingReason = null;\n    updateStatus();\n  });\n\n  \u002F\u002F Capture the cause of a close, BEFORE the async toggle fires.\n  trigger.addEventListener(\"click\", () => {\n    if (pop.matches(\":popover-open\")) pendingReason = \"you clicked the toggle button again\";\n  });\n  document.addEventListener(\n    \"keydown\",\n    (e) => {\n      if (e.key === \"Escape\" && isAuto() && pop.matches(\":popover-open\"))\n        pendingReason = \"you pressed the Escape key\";\n    },\n    true\n  );\n  document.addEventListener(\n    \"pointerdown\",\n    (e) => {\n      if (\n        isAuto() &&\n        pop.matches(\":popover-open\") &&\n        !pop.contains(e.target) &&\n        !trigger.contains(e.target) &&\n        !confirmPop.contains(e.target)\n      ) {\n        pendingReason = \"you clicked outside — light dismiss\";\n      }\n    },\n    true\n  );\n  \u002F\u002F The explicit Close button inside the card.\n  pop.querySelector('[popovertargetaction=\"hide\"]').addEventListener(\"click\", () => {\n    pendingReason = \"you hit the Close button (hidePopover)\";\n  });\n\n  \u002F\u002F Knob 1 — auto vs manual dismiss (main popover only; nested one stays auto).\n  const modeBtns = document.querySelectorAll(\".seg button\");\n  function setMode(mode, silent) {\n    if (pop.matches(\":popover-open\")) {\n      pendingReason = \"the dismiss mode changed\";\n      pop.hidePopover();\n    }\n    pop.setAttribute(\"popover\", mode);\n    modeBtns.forEach((b) => b.setAttribute(\"aria-pressed\", String(b.dataset.mode === mode)));\n    modeHint.textContent =\n      mode === \"manual\"\n        ? \"manual: clicking outside and Esc now do nothing — only the Close button (hidePopover) dismisses it.\"\n        : \"auto: click outside or press Esc to dismiss, and only one auto popover is open at a time.\";\n    if (!silent) log(\"popover=\", mode, \"info\");\n    updateStatus();\n  }\n  modeBtns.forEach((b) => b.addEventListener(\"click\", () => setMode(b.dataset.mode)));\n\n  \u002F\u002F Knob 2 — @starting-style entrance animation on\u002Foff.\n  animChk.addEventListener(\"change\", () => {\n    document.body.classList.toggle(\"anim\", animChk.checked);\n    log(\"animation\", animChk.checked ? \"@starting-style on\" : \"off (instant)\", \"info\");\n  });\n\n  \u002F\u002F Reset path — back to defaults, clear the log.\n  $(\"reset\").addEventListener(\"click\", () => {\n    if (pop.matches(\":popover-open\")) pop.hidePopover();\n    if (confirmPop.matches(\":popover-open\")) confirmPop.hidePopover();\n    setMode(\"auto\", true);\n    animChk.checked = true;\n    document.body.classList.add(\"anim\");\n    logEl.innerHTML = \"\";\n    updateStatus();\n  });\n\n  updateStatus();",{"height":40,"autorun":17},520,{"slug":33,"title":42,"excerpt":43,"coverUrl":44},"Your dropdown is a div. The browser has a native popover now.","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"]