[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-dialog-element-native-modal":44,"search-suggestions":284,"path-membership-dialog-element-native-modal":326,"related-dialog-element-native-modal":340,"code:html:true:wq47fe":466,"code:js:true:1eiyx74":467,"code:js:true:1qc3e5v":468,"code:css:true:1s7n687":469,"code:css:true:yxwz0r":470,"code:js:true:5ev235":471,"code:js:true:1e0b9ol":472,"code:html:true:6lu25e":473,"code:js:true:8a5z67":474,"comments-019ff19b-f388-73f8-aa5b-93d73337d6fd":475},[4,20,32],{"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","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","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.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,{"id":45,"slug":46,"title":47,"subtitle":48,"excerpt":49,"coverUrl":50,"locale":13,"readingMinutes":51,"publishedAt":52,"viewCount":53,"likeCount":19,"commentCount":19,"author":54,"vertical":59,"topic":60,"tags":63,"_count":75,"playground":77,"body":79,"bodyMd":267,"seo":268,"translationGroupId":271,"series":48,"podcastUrl":48,"verticalId":5,"thread":272,"assessments":274,"translations":280,"quiz":282},"019ff19b-f388-73f8-aa5b-93d73337d6fd","dialog-element-native-modal","You built your modal with a `\u003Cdiv>` and a focus trap library. The native `\u003Cdialog>` does all of that.",null,"The `\u003Cdialog>` element ships with focus trapping, Escape-to-close, backdrop rendering, and correct ARIA semantics — no library, no boilerplate. It's been Baseline since 2022.","\u002Fmedia\u002Fcovers\u002Fdialog-element-native-modal.png",5,"2026-08-08T07:00:10.810Z",654,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},"html","HTML",[64,66,69,72],{"slug":61,"name":65,"color":48},"Html",{"slug":67,"name":68,"color":48},"webdev","Webdev",{"slug":70,"name":71,"color":48},"frontend","Frontend",{"slug":73,"name":74,"color":48},"javascript","Javascript",{"assessments":76},1,{"slug":46,"title":78},"&lt;dialog&gt; — interactive playground",{"blocks":80,"version":76},[81,85,88,92,97,102,105,109,112,115,118,122,125,128,133,136,139,142,146,149,152,155,159,162,166,169,173,176,180,183,187,191,194,197,200,203,206,209,212,215,218,221,224,227,230,233,236,239,242,249,252,255,258,261],{"id":82,"html":83,"type":84},"b1","\u003Cp>Building a modal from scratch means writing the same boilerplate every time: a \u003Ccode>&lt;div&gt;\u003C\u002Fcode> with \u003Ccode>role=&quot;dialog&quot;\u003C\u002Fcode>, an \u003Ccode>aria-modal\u003C\u002Fcode> attribute, a \u003Ccode>tabindex=&quot;-1&quot;\u003C\u002Fcode> to steal focus, a \u003Ccode>keydown\u003C\u002Fcode> listener to catch Escape, a focus-trap library to keep Tab cycling inside the dialog, and a \u003Ccode>click\u003C\u002Fcode> listener on the backdrop overlay you rendered yourself. It works, but you&#39;re doing the browser&#39;s job.\u003C\u002Fp>","paragraph",{"id":86,"html":87,"type":84},"b2","\u003Cp>The \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> element exists to take that job back.\u003C\u002Fp>",{"id":89,"html":90,"text":90,"type":91,"level":31},"b3","The baseline API","heading",{"id":93,"code":94,"type":95,"language":61,"highlight":96},"b4","\u003Cdialog id=\"confirm-dialog\">\n  \u003Ch2>Delete item?\u003C\u002Fh2>\n  \u003Cp>This cannot be undone.\u003C\u002Fp>\n  \u003Cbutton id=\"cancel-btn\">Cancel\u003C\u002Fbutton>\n  \u003Cbutton id=\"confirm-btn\">Confirm\u003C\u002Fbutton>\n\u003C\u002Fdialog>\n\n\u003Cbutton id=\"open-btn\">Delete\u003C\u002Fbutton>","code",[],{"id":98,"code":99,"type":95,"language":100,"highlight":101},"b5","const dialog = document.getElementById('confirm-dialog');\nconst openBtn = document.getElementById('open-btn');\nconst cancelBtn = document.getElementById('cancel-btn');\nconst confirmBtn = document.getElementById('confirm-btn');\n\nopenBtn.addEventListener('click', () => dialog.showModal());\ncancelBtn.addEventListener('click', () => dialog.close());\nconfirmBtn.addEventListener('click', () => {\n  deleteItem();\n  dialog.close();\n});","js",[],{"id":103,"html":104,"type":84},"b6","\u003Cp>That&#39;s it. The browser handles focus trapping (Tab stays inside), Escape-to-close, and ARIA role. No library. No \u003Ccode>keydown\u003C\u002Fcode> listener. No backdrop div.\u003C\u002Fp>",{"id":106,"html":107,"text":108,"type":91,"level":31},"b7","\u003Ccode>showModal()\u003C\u002Fcode> vs \u003Ccode>show()\u003C\u002Fcode>","showModal() vs show()",{"id":110,"html":111,"type":84},"b8","\u003Cp>The element has two open methods and they are meaningfully different.\u003C\u002Fp>",{"id":113,"html":114,"type":84},"b9","\u003Cp>\u003Ccode>dialog.show()\u003C\u002Fcode> opens the dialog as a \u003Cstrong>non-modal\u003C\u002Fstrong>: it&#39;s visible, but the rest of the page is still interactive. Useful for inline panels, drawers, or toasts — not for blocking confirmation flows.\u003C\u002Fp>",{"id":116,"html":117,"type":84},"b10","\u003Cp>\u003Ccode>dialog.showModal()\u003C\u002Fcode> opens it as a \u003Cstrong>modal\u003C\u002Fstrong>: the browser places the dialog in the \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FGlossary\u002FTop_layer\">top layer\u003C\u002Fa> — above all other content, including elements with high \u003Ccode>z-index\u003C\u002Fcode> — and blocks interaction with everything beneath. Focus is trapped inside. Escape closes it. This is what you actually want for a modal dialog.\u003C\u002Fp>",{"id":119,"code":120,"type":95,"language":100,"highlight":121},"b11","dialog.show();      \u002F\u002F non-modal — rest of page still interactive\ndialog.showModal(); \u002F\u002F modal — top layer, focus trapped, Escape works",[],{"id":123,"html":124,"text":124,"type":91,"level":31},"b12","Styling the backdrop",{"id":126,"html":127,"type":84},"b13","\u003Cp>When opened with \u003Ccode>showModal()\u003C\u002Fcode>, the browser renders a backdrop behind the dialog and above the rest of the page. You style it with the \u003Ccode>::backdrop\u003C\u002Fcode> pseudo-element:\u003C\u002Fp>",{"id":129,"code":130,"type":95,"language":131,"highlight":132},"b14","dialog::backdrop {\n  background: rgb(0 0 0 \u002F 50%);\n  backdrop-filter: blur(4px);\n}","css",[],{"id":134,"html":135,"type":84},"b15","\u003Cp>No more \u003Ccode>position: fixed; inset: 0; background: rgba(0,0,0,0.5)\u003C\u002Fcode> divs. The browser-rendered backdrop is always in the right place, covers the right things, and is animated by the dialog&#39;s own open\u002Fclose transitions.\u003C\u002Fp>",{"id":137,"html":138,"text":138,"type":91,"level":31},"b16","Animating open and close",{"id":140,"html":141,"type":84},"b17","\u003Cp>The \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> element pairs naturally with \u003Ccode>@starting-style\u003C\u002Fcode> for entry animations. For the exit, you need a small JS helper because the dialog&#39;s \u003Ccode>close()\u003C\u002Fcode> method removes the \u003Ccode>open\u003C\u002Fcode> attribute before a CSS exit transition can play:\u003C\u002Fp>",{"id":143,"code":144,"type":95,"language":131,"highlight":145},"b18","dialog {\n  opacity: 0;\n  transform: scale(0.95);\n  transition: opacity 200ms, transform 200ms, display 200ms allow-discrete;\n}\n\ndialog[open] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n@starting-style {\n  dialog[open] {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n}",[],{"id":147,"html":148,"type":84},"b19","\u003Cp>With \u003Ccode>allow-discrete\u003C\u002Fcode> on the \u003Ccode>display\u003C\u002Fcode> transition (Chrome 117+), the browser holds the dialog in the layout for the duration of the exit transition before hiding it. For older targets, a small \u003Ccode>setTimeout\u003C\u002Fcode> before \u003Ccode>dialog.close()\u003C\u002Fcode> is the reliable fallback.\u003C\u002Fp>",{"id":150,"html":151,"text":151,"type":91,"level":31},"b20","Handling backdrop clicks to close",{"id":153,"html":154,"type":84},"b21","\u003Cp>The backdrop is not a separate element you can listen to directly. The reliable pattern uses the dialog&#39;s own \u003Ccode>click\u003C\u002Fcode> event and checks whether the click landed inside the dialog&#39;s bounding box:\u003C\u002Fp>",{"id":156,"code":157,"type":95,"language":100,"highlight":158},"b22","dialog.addEventListener('click', (event) => {\n  const rect = dialog.getBoundingClientRect();\n  const clickedOutside =\n    event.clientX \u003C rect.left ||\n    event.clientX > rect.right ||\n    event.clientY \u003C rect.top ||\n    event.clientY > rect.bottom;\n\n  if (clickedOutside) dialog.close();\n});",[],{"id":160,"html":161,"type":84},"b23","\u003Cp>The reason this works: when you click the backdrop, the \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> element itself receives the event — the click target is the dialog, not an element inside it. The bounding box check distinguishes backdrop clicks from content clicks cleanly.\u003C\u002Fp>",{"id":163,"html":164,"text":165,"type":91,"level":31},"b24","Return value from \u003Ccode>close()\u003C\u002Fcode>","Return value from close()",{"id":167,"html":168,"type":84},"b25","\u003Cp>\u003Ccode>dialog.close()\u003C\u002Fcode> accepts an optional string argument that becomes the dialog&#39;s \u003Ccode>returnValue\u003C\u002Fcode>. This lets you communicate \u003Cem>why\u003C\u002Fem> the dialog closed without external state:\u003C\u002Fp>",{"id":170,"code":171,"type":95,"language":100,"highlight":172},"b26","confirmBtn.addEventListener('click', () => dialog.close('confirmed'));\ncancelBtn.addEventListener('click', () => dialog.close('cancelled'));\n\ndialog.addEventListener('close', () => {\n  if (dialog.returnValue === 'confirmed') deleteItem();\n});",[],{"id":174,"html":175,"type":84},"b27","\u003Cp>The \u003Ccode>close\u003C\u002Fcode> event fires whenever the dialog closes — via \u003Ccode>close()\u003C\u002Fcode>, Escape, or a \u003Ccode>&lt;form method=&quot;dialog&quot;&gt;\u003C\u002Fcode> submission. Combined with \u003Ccode>returnValue\u003C\u002Fcode>, it gives you a clean interface for confirmation flows without threading state through callbacks.\u003C\u002Fp>",{"id":177,"html":178,"text":179,"type":91,"level":31},"b28","The \u003Ccode>&lt;form method=&quot;dialog&quot;&gt;\u003C\u002Fcode> shortcut","The \u003Cform method=\"dialog\"> shortcut",{"id":181,"html":182,"type":84},"b29","\u003Cp>If you put a \u003Ccode>&lt;form method=&quot;dialog&quot;&gt;\u003C\u002Fcode> inside a \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode>, any submit button closes the dialog automatically and sets \u003Ccode>returnValue\u003C\u002Fcode> to the button&#39;s \u003Ccode>value\u003C\u002Fcode> attribute — no JavaScript needed for the close logic:\u003C\u002Fp>",{"id":184,"code":185,"type":95,"language":61,"highlight":186},"b30","\u003Cdialog id=\"confirm-dialog\">\n  \u003Cform method=\"dialog\">\n    \u003Ch2>Delete item?\u003C\u002Fh2>\n    \u003Cbutton value=\"cancelled\">Cancel\u003C\u002Fbutton>\n    \u003Cbutton value=\"confirmed\">Confirm\u003C\u002Fbutton>\n  \u003C\u002Fform>\n\u003C\u002Fdialog>",[],{"id":188,"code":189,"type":95,"language":100,"highlight":190},"b31","dialog.addEventListener('close', () => {\n  if (dialog.returnValue === 'confirmed') deleteItem();\n});",[],{"id":192,"html":193,"type":84},"b32","\u003Cp>The form doesn&#39;t submit to a server — \u003Ccode>method=&quot;dialog&quot;\u003C\u002Fcode> is a special value that routes the submission back to the dialog element itself. Useful for simple flows; for complex forms with validation, you&#39;ll still handle submission explicitly.\u003C\u002Fp>",{"id":195,"html":196,"text":196,"type":91,"level":31},"b33","Browser support",{"id":198,"html":199,"type":84},"b34","\u003Cp>\u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> is \u003Cstrong>Baseline 2022\u003C\u002Fstrong>: Chrome 98, Firefox 98, Safari 15.4. Global support is above 95%. You do not need a polyfill for production today. The only missing piece in some older browsers is \u003Ccode>::backdrop\u003C\u002Fcode> styling — the functional modal behavior (focus trap, Escape, top layer) is universally supported.\u003C\u002Fp>",{"id":201,"html":202,"type":84},"b35","\u003C!-- playground:start -->",{"id":204,"html":205,"text":205,"type":91,"level":31},"b36","🎮 Try it yourself",{"id":207,"html":208,"type":84},"b37","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":210,"html":211,"type":84},"b38","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":213,"html":214,"type":84},"b39","\u003C!-- playground:end -->",{"id":216,"html":217,"type":84},"b40","\u003C!-- quiz:start -->",{"id":219,"html":220,"text":220,"type":91,"level":31},"b41","🧠 Test yourself",{"id":222,"html":223,"type":84},"b42","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal\u002Fquiz\">Take the 8-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":225,"html":226,"type":84},"b43","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":228,"html":229,"type":84},"b44","\u003C!-- quiz:end -->",{"id":231,"html":232,"text":232,"type":91,"level":31},"b45","The takeaway",{"id":234,"html":235,"type":84},"b46","\u003Cp>Search your codebase for \u003Ccode>role=&quot;dialog&quot;\u003C\u002Fcode> and the focus-trap imports that live near it. Each one is a candidate for replacement: \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> with \u003Ccode>showModal()\u003C\u002Fcode> handles focus trapping, Escape, backdrop, and ARIA semantics — a library bought you those because the platform didn&#39;t provide them. It does now. Start with the simplest confirmation dialog in your UI, replace it with \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> and \u003Ccode>showModal()\u003C\u002Fcode>, and you&#39;ll notice what disappears: the \u003Ccode>keydown\u003C\u002Fcode> listener, the backdrop div, the z-index war, and the focus-management ceremony. What remains is the logic that was actually yours to write.\u003C\u002Fp>",{"id":237,"html":238,"type":84},"b47","\u003C!-- related:start -->",{"id":240,"html":241,"text":241,"type":91,"level":31},"b48","📚 Read next",{"id":243,"type":244,"items":245,"ordered":18},"b49","list",[246,247,248],"\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Finert-attribute-disable-interaction\">The Modal Was Open. So Was Everything Behind It.\u003C\u002Fa>","\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fpopover-api-native-popovers\">Your dropdown is a div. The browser has a native popover now.\u003C\u002Fa>","\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-focus-visible-keyboard-focus-rings\">Stop Using outline: none. Use :focus-visible Instead.\u003C\u002Fa>",{"id":250,"html":251,"type":84},"b50","\u003C!-- related:end -->",{"id":253,"type":254},"b51","divider",{"id":256,"html":257,"type":84},"b52","\u003Cp>🚀 \u003Cstrong>Want more like this?\u003C\u002Fstrong> Every guide, playground, and quiz lives on \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">bestpractic.org\u003C\u002Fa>\u003C\u002Fstrong> — open it and \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">sign up free\u003C\u002Fa>\u003C\u002Fstrong> so the next one finds you.\u003C\u002Fp>",{"id":259,"html":260,"type":84},"b53","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":262,"type":244,"items":263,"ordered":18},"b54",[264,265,266],"⭐ \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>","Building a modal from scratch means writing the same boilerplate every time: a `\u003Cdiv>` with `role=\"dialog\"`, an `aria-modal` attribute, a `tabindex=\"-1\"` to steal focus, a `keydown` listener to catch Escape, a focus-trap library to keep Tab cycling inside the dialog, and a `click` listener on the backdrop overlay you rendered yourself. It works, but you're doing the browser's job.\n\nThe `\u003Cdialog>` element exists to take that job back.\n\n## The baseline API\n\n```html\n\u003Cdialog id=\"confirm-dialog\">\n  \u003Ch2>Delete item?\u003C\u002Fh2>\n  \u003Cp>This cannot be undone.\u003C\u002Fp>\n  \u003Cbutton id=\"cancel-btn\">Cancel\u003C\u002Fbutton>\n  \u003Cbutton id=\"confirm-btn\">Confirm\u003C\u002Fbutton>\n\u003C\u002Fdialog>\n\n\u003Cbutton id=\"open-btn\">Delete\u003C\u002Fbutton>\n```\n\n```js\nconst dialog = document.getElementById('confirm-dialog');\nconst openBtn = document.getElementById('open-btn');\nconst cancelBtn = document.getElementById('cancel-btn');\nconst confirmBtn = document.getElementById('confirm-btn');\n\nopenBtn.addEventListener('click', () => dialog.showModal());\ncancelBtn.addEventListener('click', () => dialog.close());\nconfirmBtn.addEventListener('click', () => {\n  deleteItem();\n  dialog.close();\n});\n```\n\nThat's it. The browser handles focus trapping (Tab stays inside), Escape-to-close, and ARIA role. No library. No `keydown` listener. No backdrop div.\n\n## `showModal()` vs `show()`\n\nThe element has two open methods and they are meaningfully different.\n\n`dialog.show()` opens the dialog as a **non-modal**: it's visible, but the rest of the page is still interactive. Useful for inline panels, drawers, or toasts — not for blocking confirmation flows.\n\n`dialog.showModal()` opens it as a **modal**: the browser places the dialog in the [top layer](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FGlossary\u002FTop_layer) — above all other content, including elements with high `z-index` — and blocks interaction with everything beneath. Focus is trapped inside. Escape closes it. This is what you actually want for a modal dialog.\n\n```js\ndialog.show();      \u002F\u002F non-modal — rest of page still interactive\ndialog.showModal(); \u002F\u002F modal — top layer, focus trapped, Escape works\n```\n\n## Styling the backdrop\n\nWhen opened with `showModal()`, the browser renders a backdrop behind the dialog and above the rest of the page. You style it with the `::backdrop` pseudo-element:\n\n```css\ndialog::backdrop {\n  background: rgb(0 0 0 \u002F 50%);\n  backdrop-filter: blur(4px);\n}\n```\n\nNo more `position: fixed; inset: 0; background: rgba(0,0,0,0.5)` divs. The browser-rendered backdrop is always in the right place, covers the right things, and is animated by the dialog's own open\u002Fclose transitions.\n\n## Animating open and close\n\nThe `\u003Cdialog>` element pairs naturally with `@starting-style` for entry animations. For the exit, you need a small JS helper because the dialog's `close()` method removes the `open` attribute before a CSS exit transition can play:\n\n```css\ndialog {\n  opacity: 0;\n  transform: scale(0.95);\n  transition: opacity 200ms, transform 200ms, display 200ms allow-discrete;\n}\n\ndialog[open] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n@starting-style {\n  dialog[open] {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n}\n```\n\nWith `allow-discrete` on the `display` transition (Chrome 117+), the browser holds the dialog in the layout for the duration of the exit transition before hiding it. For older targets, a small `setTimeout` before `dialog.close()` is the reliable fallback.\n\n## Handling backdrop clicks to close\n\nThe backdrop is not a separate element you can listen to directly. The reliable pattern uses the dialog's own `click` event and checks whether the click landed inside the dialog's bounding box:\n\n```js\ndialog.addEventListener('click', (event) => {\n  const rect = dialog.getBoundingClientRect();\n  const clickedOutside =\n    event.clientX \u003C rect.left ||\n    event.clientX > rect.right ||\n    event.clientY \u003C rect.top ||\n    event.clientY > rect.bottom;\n\n  if (clickedOutside) dialog.close();\n});\n```\n\nThe reason this works: when you click the backdrop, the `\u003Cdialog>` element itself receives the event — the click target is the dialog, not an element inside it. The bounding box check distinguishes backdrop clicks from content clicks cleanly.\n\n## Return value from `close()`\n\n`dialog.close()` accepts an optional string argument that becomes the dialog's `returnValue`. This lets you communicate *why* the dialog closed without external state:\n\n```js\nconfirmBtn.addEventListener('click', () => dialog.close('confirmed'));\ncancelBtn.addEventListener('click', () => dialog.close('cancelled'));\n\ndialog.addEventListener('close', () => {\n  if (dialog.returnValue === 'confirmed') deleteItem();\n});\n```\n\nThe `close` event fires whenever the dialog closes — via `close()`, Escape, or a `\u003Cform method=\"dialog\">` submission. Combined with `returnValue`, it gives you a clean interface for confirmation flows without threading state through callbacks.\n\n## The `\u003Cform method=\"dialog\">` shortcut\n\nIf you put a `\u003Cform method=\"dialog\">` inside a `\u003Cdialog>`, any submit button closes the dialog automatically and sets `returnValue` to the button's `value` attribute — no JavaScript needed for the close logic:\n\n```html\n\u003Cdialog id=\"confirm-dialog\">\n  \u003Cform method=\"dialog\">\n    \u003Ch2>Delete item?\u003C\u002Fh2>\n    \u003Cbutton value=\"cancelled\">Cancel\u003C\u002Fbutton>\n    \u003Cbutton value=\"confirmed\">Confirm\u003C\u002Fbutton>\n  \u003C\u002Fform>\n\u003C\u002Fdialog>\n```\n\n```js\ndialog.addEventListener('close', () => {\n  if (dialog.returnValue === 'confirmed') deleteItem();\n});\n```\n\nThe form doesn't submit to a server — `method=\"dialog\"` is a special value that routes the submission back to the dialog element itself. Useful for simple flows; for complex forms with validation, you'll still handle submission explicitly.\n\n## Browser support\n\n`\u003Cdialog>` is **Baseline 2022**: Chrome 98, Firefox 98, Safari 15.4. Global support is above 95%. You do not need a polyfill for production today. The only missing piece in some older browsers is `::backdrop` styling — the functional modal behavior (focus trap, Escape, top layer) is universally supported.\n\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal\u002Fplayground)**\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 8-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n## The takeaway\n\nSearch your codebase for `role=\"dialog\"` and the focus-trap imports that live near it. Each one is a candidate for replacement: `\u003Cdialog>` with `showModal()` handles focus trapping, Escape, backdrop, and ARIA semantics — a library bought you those because the platform didn't provide them. It does now. Start with the simplest confirmation dialog in your UI, replace it with `\u003Cdialog>` and `showModal()`, and you'll notice what disappears: the `keydown` listener, the backdrop div, the z-index war, and the focus-management ceremony. What remains is the logic that was actually yours to write.\n\n\u003C!-- related:start -->\n\n## 📚 Read next\n\n- [The Modal Was Open. So Was Everything Behind It.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Finert-attribute-disable-interaction)\n- [Your dropdown is a div. The browser has a native popover now.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fpopover-api-native-popovers)\n- [Stop Using outline: none. Use :focus-visible Instead.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-focus-visible-keyboard-focus-rings)\n\n\u003C!-- related:end -->\n\n---\n\n🚀 **Want more like this?** Every guide, playground, and quiz lives on **[bestpractic.org](https:\u002F\u002Fbestpractic.org\u002F)** — open it and **[sign up free](https:\u002F\u002Fbestpractic.org\u002F)** so the next one finds you.\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)",{"title":269,"canonical":270,"description":49},"You built your modal with a `\u003Cdiv>` and a focus trap library. The nati","https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal","019ff19b-f388-73f8-aa5b-97670f13d581",{"id":273,"locked":18},"019ff19b-f3a1-7259-882a-24fdc8bb3f32",[275],{"id":276,"slug":46,"title":277,"_count":278},"019ff19b-f3ba-73aa-9313-c2d3237b0363","Native \u003Cdialog> element",{"questions":279},8,[281],{"locale":13,"slug":46},{"id":276,"slug":46,"title":277,"_count":283,"questionCount":279},{"questions":279},[285,287,289,291,295,298,302,306,310,314,318,322],{"slug":67,"name":68,"articles":286},139,{"slug":73,"name":74,"articles":288},113,{"slug":70,"name":71,"articles":290},84,{"slug":292,"name":293,"articles":294},"tutorial","Tutorial",53,{"slug":131,"name":296,"articles":297},"Css",42,{"slug":299,"name":300,"articles":301},"performance","Performance",21,{"slug":303,"name":304,"articles":305},"typescript","Typescript",18,{"slug":307,"name":308,"articles":309},"react","React",17,{"slug":311,"name":312,"articles":313},"browser","Browser",13,{"slug":315,"name":316,"articles":317},"node","Node",12,{"slug":319,"name":320,"articles":321},"programming","Programming",10,{"slug":323,"name":324,"articles":325},"accessibility","Accessibility",9,[327],{"path":328,"zone":331,"level":332,"next":336},{"slug":329,"title":330,"accentFrom":10,"accentTo":11},"frontend-developer","Frontend Developer",{"slug":61,"title":62,"tier":76},{"id":333,"label":334,"number":76,"of":335},"01a13a8c-af08-7228-a6be-928a0c118889","Native \u003Cdialog>",4,{"id":337,"label":338,"slug":339},"01a13a8c-af08-7228-a6be-96b69ebff266","Exclusive accordions","details-name-exclusive-accordion",{"items":341,"meta":464},[342,360,379,398,416,434,452],{"id":343,"slug":339,"title":344,"subtitle":48,"excerpt":345,"coverUrl":346,"locale":13,"readingMinutes":347,"publishedAt":348,"viewCount":349,"likeCount":19,"commentCount":19,"author":350,"vertical":351,"topic":352,"tags":353,"_count":358,"playground":359,"hasQuiz":17,"hasPlayground":17},"01a0ec73-289b-72dc-b408-cb3deb2a38a9","Stop Hand-Rolling an Exclusive Accordion. `\u003Cdetails name>` Does It","You've probably shipped an accordion with a hand-rolled 'close the other panels' loop in JavaScript. The `name` attribute on \u003Cdetails> does it natively — no JS, no ARIA plumbing.","\u002Fmedia\u002Fcovers\u002Fdetails-name-exclusive-accordion.png",6,"2026-10-04T12:03:17.379Z",370,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[354,355,356,357],{"slug":61,"name":65,"color":48},{"slug":131,"name":296,"color":48},{"slug":67,"name":68,"color":48},{"slug":323,"name":324,"color":48},{"assessments":76},{"slug":339},{"id":361,"slug":362,"title":363,"subtitle":48,"excerpt":364,"coverUrl":365,"locale":13,"readingMinutes":347,"publishedAt":366,"viewCount":367,"likeCount":19,"commentCount":19,"author":368,"vertical":369,"topic":370,"tags":372,"_count":377,"playground":378,"hasQuiz":17,"hasPlayground":17},"01a0b426-701c-74eb-b94f-6cad6f72a710","formdata-file-upload-json-stringify-trap","JSON.stringify Is Quietly Deleting Your File Uploads","An avatar upload form that passes every test, ships to production, returns 200 OK — and never actually uploads the picture. The bug is one function call that silently turns a File into an empty object, with no error anywhere.","\u002Fmedia\u002Fcovers\u002Fformdata-file-upload-json-stringify-trap.png","2026-09-26T12:24:36.794Z",356,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":73,"name":371},"JavaScript",[373,374,375,376],{"slug":73,"name":74,"color":48},{"slug":67,"name":68,"color":48},{"slug":292,"name":293,"color":48},{"slug":61,"name":65,"color":48},{"assessments":76},{"slug":362},{"id":380,"slug":381,"title":382,"subtitle":48,"excerpt":383,"coverUrl":384,"locale":13,"readingMinutes":51,"publishedAt":385,"viewCount":386,"likeCount":19,"commentCount":19,"author":387,"vertical":388,"topic":389,"tags":391,"_count":396,"playground":397,"hasQuiz":17,"hasPlayground":17},"01a0a9ea-93a3-7734-b359-6d7cc4df502b","customizable-select-appearance-base-select","The Dropdown You've Been Faking for a Decade","Every hand-built 'custom select' with icons and a styled popup exists because the real \u003Cselect> couldn't do that. appearance: base-select just closed the gap — without you losing the native picker's keyboard nav and mobile UI.","\u002Fmedia\u002Fcovers\u002Fcustomizable-select-appearance-base-select.png","2026-09-22T19:36:39.450Z",470,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":131,"name":390},"CSS",[392,393,394,395],{"slug":131,"name":296,"color":48},{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":323,"name":324,"color":48},{"assessments":76},{"slug":381},{"id":399,"slug":400,"title":401,"subtitle":48,"excerpt":402,"coverUrl":403,"locale":13,"readingMinutes":347,"publishedAt":404,"viewCount":405,"likeCount":19,"commentCount":19,"author":406,"vertical":407,"topic":408,"tags":409,"_count":414,"playground":415,"hasQuiz":17,"hasPlayground":17},"01a09fda-b750-710a-9a40-8113c1d054b3","drag-drop-api-dragover-preventdefault-trap","Your Browser Is Rejecting Every Drop On Purpose","A drop zone with a correctly wired drop listener that never fires — no error, no typo, nothing in the console. The browser is silently refusing the drop by design, and only one specific line stops it.","\u002Fmedia\u002Fcovers\u002Fdrag-drop-api-dragover-preventdefault-trap.png","2026-09-20T16:26:35.914Z",369,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":73,"name":371},[410,411,412,413],{"slug":73,"name":74,"color":48},{"slug":67,"name":68,"color":48},{"slug":61,"name":65,"color":48},{"slug":292,"name":293,"color":48},{"assessments":76},{"slug":400},{"id":417,"slug":418,"title":419,"subtitle":48,"excerpt":420,"coverUrl":421,"locale":13,"readingMinutes":51,"publishedAt":422,"viewCount":423,"likeCount":19,"commentCount":19,"author":424,"vertical":425,"topic":426,"tags":427,"_count":432,"playground":433,"hasQuiz":17,"hasPlayground":17},"01a0499d-bb9f-709b-9e8a-9c426ae95530","declarative-shadow-dom-ssr-web-components","Shadow DOM Needed JavaScript to Exist. Now It Doesn't.","attachShadow() is a JavaScript-only API with no HTML serialization, so a server-rendered web component ships an empty host element until the client hydrates it. Declarative Shadow DOM attaches the real shadow root during HTML parsing — zero JS required.","\u002Fmedia\u002Fcovers\u002Fdeclarative-shadow-dom-ssr-web-components.png","2026-09-02T10:57:52.645Z",412,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":73,"name":371},[428,429,430,431],{"slug":67,"name":68,"color":48},{"slug":73,"name":74,"color":48},{"slug":61,"name":65,"color":48},{"slug":70,"name":71,"color":48},{"assessments":76},{"slug":418},{"id":435,"slug":436,"title":437,"subtitle":48,"excerpt":438,"coverUrl":439,"locale":13,"readingMinutes":347,"publishedAt":440,"viewCount":441,"likeCount":19,"commentCount":19,"author":442,"vertical":443,"topic":444,"tags":445,"_count":450,"playground":451,"hasQuiz":17,"hasPlayground":17},"01a00e88-aad0-7555-be95-4e472b212b9b","inert-attribute-disable-interaction","The Modal Was Open. So Was Everything Behind It.","A keyboard-only pass found a background button still worked while a modal was open — aria-hidden had hidden it from screen readers but never touched focus or clicks. One boolean attribute, inert, closes that gap in a single line.","\u002Fmedia\u002Fcovers\u002Finert-attribute-disable-interaction.png","2026-08-21T06:54:17.247Z",457,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[446,447,448,449],{"slug":61,"name":65,"color":48},{"slug":323,"name":324,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"assessments":76},{"slug":436},{"id":45,"slug":46,"title":47,"subtitle":48,"excerpt":49,"coverUrl":50,"locale":13,"readingMinutes":51,"publishedAt":52,"viewCount":453,"likeCount":19,"commentCount":19,"author":454,"vertical":455,"topic":456,"tags":457,"_count":462,"playground":463,"hasQuiz":17,"hasPlayground":17},655,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[458,459,460,461],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":73,"name":74,"color":48},{"assessments":76},{"slug":46},{"page":76,"perPage":465,"total":325,"totalPages":31},7,"\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>\u003Cdiv>8\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\">dialog\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\">\"confirm-dialog\"\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\">h2\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Delete item?\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">h2\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\">p\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>This cannot be undone.\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">p\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\">button\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\">\"cancel-btn\"\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Cancel\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  \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">button\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\">\"confirm-btn\"\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Confirm\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\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">dialog\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\">button\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\">\"open-btn\"\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\">button\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>\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\">const\u003C\u002Fspan> dialog \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\">'confirm-dialog'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> openBtn \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\">'open-btn'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> cancelBtn \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\">'cancel-btn'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> confirmBtn \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\">'confirm-btn'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\nopenBtn\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">showModal\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\ncancelBtn\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">close\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\nconfirmBtn\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\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-func\">deleteItem\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">close\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">show\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;      \u003Cspan class=\"shj-cmnt\">\u002F\u002F non-modal — rest of page still interactive\n\u003C\u002Fspan>dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">showModal\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>; \u003Cspan class=\"shj-cmnt\">\u002F\u002F modal — top layer, focus trapped, Escape works\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">dialog\u003C\u002Fspan>\u003Cspan class=\"shj-var\">::backdrop\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">background\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">rgb\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">0\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0\u003C\u002Fspan> \u002F \u003Cspan class=\"shj-num\">50\u003C\u002Fspan>\u003Cspan class=\"shj-var\">%\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">backdrop-filter\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">blur\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">4\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>\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">dialog\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\">scale\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">0.95\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">transition\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">opacity\u003C\u002Fspan> \u003Cspan class=\"shj-num\">200\u003C\u002Fspan>ms, \u003Cspan class=\"shj-num\">transform\u003C\u002Fspan> \u003Cspan class=\"shj-num\">200\u003C\u002Fspan>ms, \u003Cspan class=\"shj-num\">display\u003C\u002Fspan> \u003Cspan class=\"shj-num\">200\u003C\u002Fspan>ms \u003Cspan class=\"shj-num\">allow-discrete\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">dialog\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">open\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\">1\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">scale\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">1\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-kwd\">dialog\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">open\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\">scale\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">0.95\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>","\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>event\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> rect \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">getBoundingClientRect\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> clickedOutside \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\n    event\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>clientX \u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan> rect\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>left \u003Cspan class=\"shj-oper\">||\u003C\u002Fspan>\n    event\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>clientX \u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan> rect\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>right \u003Cspan class=\"shj-oper\">||\u003C\u002Fspan>\n    event\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>clientY \u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan> rect\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>top \u003Cspan class=\"shj-oper\">||\u003C\u002Fspan>\n    event\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>clientY \u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan> rect\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>bottom;\n\n  \u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>clickedOutside\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">close\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\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>\u003Cdiv>6\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">confirmBtn\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">close\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'confirmed'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\ncancelBtn\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'click'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">close\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'cancelled'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\ndialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'close'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\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\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>returnValue \u003Cspan class=\"shj-oper\">===\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'confirmed'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-func\">deleteItem\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\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\">dialog\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\">\"confirm-dialog\"\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\">form\u003C\u002Fspan> \u003Cspan class=\"shj-class\">method\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"dialog\"\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\">h2\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Delete item?\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">h2\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\">button\u003C\u002Fspan> \u003Cspan class=\"shj-class\">value\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"cancelled\"\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Cancel\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    \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">button\u003C\u002Fspan> \u003Cspan class=\"shj-class\">value\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"confirmed\"\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Confirm\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  \u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">form\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\">dialog\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'close'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\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\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>dialog\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>returnValue \u003Cspan class=\"shj-oper\">===\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'confirmed'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-func\">deleteItem\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>",{"locked":18,"total":19,"comments":476},[]]