[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-details-name-exclusive-accordion":44,"search-suggestions":239,"related-details-name-exclusive-accordion":278,"code:js:true:1fuyva9":404,"code:html:true:w7osiu":405,"comments-01a0ec73-289b-72dc-b408-cb3deb2a38a9":406},[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":223,"seo":224,"translationGroupId":226,"series":48,"podcastUrl":48,"verticalId":5,"thread":227,"assessments":229,"translations":235,"quiz":237},"01a0ec73-289b-72dc-b408-cb3deb2a38a9","details-name-exclusive-accordion","Stop Hand-Rolling an Exclusive Accordion. `\u003Cdetails name>` Does It",null,"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",33,{"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},"css","Css",{"slug":70,"name":71,"color":48},"webdev","Webdev",{"slug":73,"name":74,"color":48},"accessibility","Accessibility",{"assessments":76},1,{"slug":46,"title":78},"&lt;details name&gt; — native accordion playground",{"blocks":80,"version":76},[81,85,88,91,95,101,104,107,110,113,117,120,123,126,129,132,135,138,145,148,151,154,157,160,163,166,169,172,175,178,181,184,187,190,193,196,199,205,208,211,214,217],{"id":82,"html":83,"type":84},"b1","\u003Cp>You&#39;re building an FAQ page. Ten questions, each collapsed by default, and — this part&#39;s in every design spec — only one answer open at a time. Click a second question, the first one closes. Standard accordion behavior, the kind you&#39;ve built before you finish reading the ticket.\u003C\u002Fp>","paragraph",{"id":86,"html":87,"type":84},"b2","\u003Cp>So you reach for \u003Ccode>&lt;details&gt;\u003C\u002Fcode> and \u003Ccode>&lt;summary&gt;\u003C\u002Fcode>, because it&#39;s the native disclosure widget and you&#39;d rather not hand-roll \u003Ccode>aria-expanded\u003C\u002Fcode> toggling again. Ten of them render fine. Then you click the second one open while the first is still open, and both sit there, expanded, taking up the whole viewport. \u003Ccode>&lt;details&gt;\u003C\u002Fcode> never promised mutual exclusivity — every element manages its own \u003Ccode>open\u003C\u002Fcode> state, full stop.\u003C\u002Fp>",{"id":89,"html":90,"type":84},"b3","\u003Cp>So you write the loop everyone writes.\u003C\u002Fp>",{"id":92,"html":93,"text":93,"type":94,"level":31},"b4","The fix everyone reaches for first","heading",{"id":96,"code":97,"type":98,"language":99,"highlight":100},"b5","const items = document.querySelectorAll(\"details.faq-item\");\n\nitems.forEach((item) => {\n  item.addEventListener(\"toggle\", () => {\n    if (!item.open) return;\n    items.forEach((other) => {\n      if (other !== item) other.open = false;\n    });\n  });\n});","code","js",[],{"id":102,"html":103,"type":84},"b6","\u003Cp>It works. It&#39;s also more surface area than it looks: a \u003Ccode>querySelectorAll\u003C\u002Fcode> scoped to a class you have to remember to apply consistently, an event listener per item, a \u003Ccode>forEach\u003C\u002Fcode> over every item each time any panel opens, whether or not anything needs to close, and a bug waiting for the first time someone copy-pastes an FAQ block without re-running the script — say, into content injected after the page loads. Miss the re-init and you&#39;re back to every panel opening independently, silently, with no error to tell you why.\u003C\u002Fp>",{"id":105,"html":106,"type":84},"b7","\u003Cp>And that&#39;s the \u003Cem>simple\u003C\u002Fem> version. The moment product wants nested accordions, or two independent FAQ groups on the same page that shouldn&#39;t interact, this script needs scoping logic, and now it&#39;s a small state machine you&#39;re maintaining for something that reads, in the design file, as &quot;an accordion.&quot;\u003C\u002Fp>",{"id":108,"html":109,"text":109,"type":94,"level":31},"b8","What the browser already does with one word",{"id":111,"html":112,"type":84},"b9","\u003Cp>Since late 2023 (Chrome 120, Safari 17.2; Firefox followed in 130, September 2024), \u003Ccode>&lt;details&gt;\u003C\u002Fcode> takes a \u003Ccode>name\u003C\u002Fcode> attribute. Give a group of them the same name, and the browser enforces the mutual exclusivity itself — open one, the others in that group close, automatically, with zero JavaScript:\u003C\u002Fp>",{"id":114,"code":115,"type":98,"language":61,"highlight":116},"b10","\u003Cdetails name=\"faq\">\n  \u003Csummary>What's your refund policy?\u003C\u002Fsummary>\n  \u003Cp>Full refund within 30 days, no questions asked.\u003C\u002Fp>\n\u003C\u002Fdetails>\n\n\u003Cdetails name=\"faq\">\n  \u003Csummary>Do you offer team plans?\u003C\u002Fsummary>\n  \u003Cp>Yes — see the pricing page for per-seat rates.\u003C\u002Fp>\n\u003C\u002Fdetails>\n\n\u003Cdetails name=\"faq\">\n  \u003Csummary>Can I cancel anytime?\u003C\u002Fsummary>\n  \u003Cp>Yes, from account settings, effective end of billing period.\u003C\u002Fp>\n\u003C\u002Fdetails>",[],{"id":118,"html":119,"type":84},"b11","\u003Cp>That&#39;s the whole implementation. It behaves like a radio group built out of disclosure widgets: same \u003Ccode>name\u003C\u002Fcode> value ties them together, opening one closes every other member of the group, and it works the instant you add another \u003Ccode>&lt;details name=&quot;faq&quot;&gt;\u003C\u002Fcode> anywhere on the page — no re-running a script, no re-scoping a selector.\u003C\u002Fp>",{"id":121,"html":122,"type":84},"b12","\u003Cp>It&#39;s Baseline-available across current Chrome, Edge, Firefox, and Safari, which means you can rely on it in a production FAQ page today. Where support is missing, the fallback isn&#39;t broken — it&#39;s just every \u003Ccode>&lt;details&gt;\u003C\u002Fcode> reverting to independent behavior, exactly like today, so nothing crashes on an older browser. That&#39;s the quiet advantage of building on a native element instead of a \u003Ccode>div\u003C\u002Fcode> with ARIA bolted on: the un-enhanced state is still a working, keyboard-accessible disclosure widget, not a blank div waiting on JS that never ran.\u003C\u002Fp>",{"id":124,"html":125,"text":125,"type":94,"level":31},"b13","The part that actually surprised me",{"id":127,"html":128,"type":84},"b14","\u003Cp>I expected the grouping to require the elements to be siblings, or at least share a parent container — that&#39;s how the radio-input-plus-CSS trick works, and it&#39;s how most accordion libraries assume you&#39;ll structure the DOM. It doesn&#39;t. The \u003Ccode>name\u003C\u002Fcode> attribute groups by value alone (within one DOM tree — a shadow root starts its own groups). Two \u003Ccode>&lt;details name=&quot;settings&quot;&gt;\u003C\u002Fcode> elements in completely different sections of the page, with unrelated markup between them, are still one exclusive group.\u003C\u002Fp>",{"id":130,"html":131,"type":84},"b15","\u003Cp>The spec allows it but advises against leaning on it: authors &quot;should keep those related elements together in a containing element,&quot; because panels that close each other from disparate corners of a page have a relationship that&#39;s hard to discover — especially with a screen reader. It&#39;s mostly the thing to watch for: reuse a \u003Ccode>name\u003C\u002Fcode> by accident — paste a component, forget to change the group id — and two accordions you meant to be independent start closing each other&#39;s panels, and there&#39;s no console warning telling you why.\u003C\u002Fp>",{"id":133,"html":134,"text":134,"type":94,"level":31},"b16","Where the JavaScript still earns its keep",{"id":136,"html":137,"type":84},"b17","\u003Cp>Native grouping replaces the \u003Cem>sibling-closing\u003C\u002Fem> loop, not everything you might want an accordion to do. You&#39;d still reach for a script if you need to:\u003C\u002Fp>",{"id":139,"type":140,"items":141,"ordered":18},"b18","list",[142,143,144],"\u003Cstrong>Open a panel from outside a click\u003C\u002Fstrong> — a &quot;Contact support&quot; button that opens the relevant answer still means setting \u003Ccode>.open = true\u003C\u002Fcode> yourself (the group then closes the others). Plain anchor links are the exception: in current browsers, following a \u003Ccode>#id\u003C\u002Fcode> that points at content \u003Cem>inside\u003C\u002Fem> a closed \u003Ccode>&lt;details&gt;\u003C\u002Fcode> expands it natively, and the \u003Ccode>name\u003C\u002Fcode> group closes whichever panel was open.","\u003Cstrong>Persist state\u003C\u002Fstrong> — remembering which panel was open across a reload is your \u003Ccode>localStorage\u003C\u002Fcode> write, same as any other piece of UI state.","\u003Cstrong>React to which one opened\u003C\u002Fstrong> — analytics on &quot;which FAQ gets clicked most&quot; still listens for the \u003Ccode>toggle\u003C\u002Fcode> event; check \u003Ccode>event.newState === &quot;open&quot;\u003C\u002Fcode>, because the sibling the browser auto-closes fires its own \u003Ccode>toggle\u003C\u002Fcode> too (with \u003Ccode>newState: &quot;closed&quot;\u003C\u002Fcode>).",{"id":146,"html":147,"type":84},"b19","\u003Cp>None of that is the accordion&#39;s core behavior, though — it&#39;s things you&#39;d bolt onto \u003Cem>any\u003C\u002Fem> accordion, native or not. The mutual-exclusivity plumbing, the part that used to be your bug to maintain, is gone.\u003C\u002Fp>",{"id":149,"html":150,"type":84},"b20","\u003Cp>Try both versions side by side below: the naive JS-loop accordion and the \u003Ccode>name\u003C\u002Fcode>-grouped native one, with a toggle to break the \u003Ccode>name\u003C\u002Fcode> value and watch two &quot;independent&quot; groups start fighting over the same state.\u003C\u002Fp>",{"id":152,"html":153,"type":84},"b21","\u003C!-- playground:start -->",{"id":155,"html":156,"text":156,"type":94,"level":31},"b22","🎮 Try it yourself",{"id":158,"html":159,"type":84},"b23","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdetails-name-exclusive-accordion\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":161,"html":162,"type":84},"b24","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":164,"html":165,"type":84},"b25","\u003C!-- playground:end -->",{"id":167,"html":168,"text":168,"type":94,"level":31},"b26","The lesson that generalizes past accordions",{"id":170,"html":171,"type":84},"b27","\u003Cp>\u003Ccode>&lt;details&gt;\u003C\u002Fcode> picked up \u003Ccode>name\u003C\u002Fcode> grouping the same way \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> picked up native modal semantics and \u003Ccode>&lt;input type=&quot;date&quot;&gt;\u003C\u002Fcode> picked up a whole calendar widget: the platform absorbing a pattern that used to be userland plumbing. The tell that it&#39;s worth checking MDN before you write the loop is exactly this shape of problem — &quot;state that needs to stay consistent across a group of elements&quot; — because that&#39;s precisely the kind of thing HTML has been quietly annexing from JavaScript for a few years now.\u003C\u002Fp>",{"id":173,"html":174,"type":84},"b28","\u003Cp>Next time you&#39;re about to write a \u003Ccode>forEach\u003C\u002Fcode> that closes siblings, checks a \u003Ccode>data-\u003C\u002Fcode> attribute, or manages &quot;only one of these is open at a time,&quot; it&#39;s worth thirty seconds on MDN before the twentieth line of the script. Sometimes the browser already shipped it.\u003C\u002Fp>",{"id":176,"html":177,"type":84},"b29","\u003Cp>What&#39;s the last bit of state-management JavaScript you wrote that turned out to already be a native HTML attribute? I&#39;ve got a second one of these for \u003Ccode>popover\u003C\u002Fcode>&#39;s \u003Ccode>popovertarget\u003C\u002Fcode> — tell me yours first.\u003C\u002Fp>",{"id":179,"html":180,"type":84},"b30","\u003C!-- quiz:start -->",{"id":182,"html":183,"text":183,"type":94,"level":31},"b31","🧠 Test yourself",{"id":185,"html":186,"type":84},"b32","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdetails-name-exclusive-accordion\u002Fquiz\">Take the 7-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":188,"html":189,"type":84},"b33","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":191,"html":192,"type":84},"b34","\u003C!-- quiz:end -->",{"id":194,"html":195,"type":84},"b35","\u003C!-- related:start -->",{"id":197,"html":198,"text":198,"type":94,"level":31},"b36","📚 Read next",{"id":200,"type":140,"items":201,"ordered":18},"b37",[202,203,204],"\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\u002Fcss-focus-visible-keyboard-focus-rings\">Stop Using outline: none. Use :focus-visible Instead.\u003C\u002Fa>","\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal\">You built your modal with a \u003Ccode>&lt;div&gt;\u003C\u002Fcode> and a focus trap library. The native \u003Ccode>&lt;dialog&gt;\u003C\u002Fcode> does all of that.\u003C\u002Fa>",{"id":206,"html":207,"type":84},"b38","\u003C!-- related:end -->",{"id":209,"type":210},"b39","divider",{"id":212,"html":213,"type":84},"b40","\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":215,"html":216,"type":84},"b41","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":218,"type":140,"items":219,"ordered":18},"b42",[220,221,222],"⭐ \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>","You're building an FAQ page. Ten questions, each collapsed by default, and — this part's in every design spec — only one answer open at a time. Click a second question, the first one closes. Standard accordion behavior, the kind you've built before you finish reading the ticket.\n\nSo you reach for `\u003Cdetails>` and `\u003Csummary>`, because it's the native disclosure widget and you'd rather not hand-roll `aria-expanded` toggling again. Ten of them render fine. Then you click the second one open while the first is still open, and both sit there, expanded, taking up the whole viewport. `\u003Cdetails>` never promised mutual exclusivity — every element manages its own `open` state, full stop.\n\nSo you write the loop everyone writes.\n\n## The fix everyone reaches for first\n\n```js\nconst items = document.querySelectorAll(\"details.faq-item\");\n\nitems.forEach((item) => {\n  item.addEventListener(\"toggle\", () => {\n    if (!item.open) return;\n    items.forEach((other) => {\n      if (other !== item) other.open = false;\n    });\n  });\n});\n```\n\nIt works. It's also more surface area than it looks: a `querySelectorAll` scoped to a class you have to remember to apply consistently, an event listener per item, a `forEach` over every item each time any panel opens, whether or not anything needs to close, and a bug waiting for the first time someone copy-pastes an FAQ block without re-running the script — say, into content injected after the page loads. Miss the re-init and you're back to every panel opening independently, silently, with no error to tell you why.\n\nAnd that's the *simple* version. The moment product wants nested accordions, or two independent FAQ groups on the same page that shouldn't interact, this script needs scoping logic, and now it's a small state machine you're maintaining for something that reads, in the design file, as \"an accordion.\"\n\n## What the browser already does with one word\n\nSince late 2023 (Chrome 120, Safari 17.2; Firefox followed in 130, September 2024), `\u003Cdetails>` takes a `name` attribute. Give a group of them the same name, and the browser enforces the mutual exclusivity itself — open one, the others in that group close, automatically, with zero JavaScript:\n\n```html\n\u003Cdetails name=\"faq\">\n  \u003Csummary>What's your refund policy?\u003C\u002Fsummary>\n  \u003Cp>Full refund within 30 days, no questions asked.\u003C\u002Fp>\n\u003C\u002Fdetails>\n\n\u003Cdetails name=\"faq\">\n  \u003Csummary>Do you offer team plans?\u003C\u002Fsummary>\n  \u003Cp>Yes — see the pricing page for per-seat rates.\u003C\u002Fp>\n\u003C\u002Fdetails>\n\n\u003Cdetails name=\"faq\">\n  \u003Csummary>Can I cancel anytime?\u003C\u002Fsummary>\n  \u003Cp>Yes, from account settings, effective end of billing period.\u003C\u002Fp>\n\u003C\u002Fdetails>\n```\n\nThat's the whole implementation. It behaves like a radio group built out of disclosure widgets: same `name` value ties them together, opening one closes every other member of the group, and it works the instant you add another `\u003Cdetails name=\"faq\">` anywhere on the page — no re-running a script, no re-scoping a selector.\n\nIt's Baseline-available across current Chrome, Edge, Firefox, and Safari, which means you can rely on it in a production FAQ page today. Where support is missing, the fallback isn't broken — it's just every `\u003Cdetails>` reverting to independent behavior, exactly like today, so nothing crashes on an older browser. That's the quiet advantage of building on a native element instead of a `div` with ARIA bolted on: the un-enhanced state is still a working, keyboard-accessible disclosure widget, not a blank div waiting on JS that never ran.\n\n## The part that actually surprised me\n\nI expected the grouping to require the elements to be siblings, or at least share a parent container — that's how the radio-input-plus-CSS trick works, and it's how most accordion libraries assume you'll structure the DOM. It doesn't. The `name` attribute groups by value alone (within one DOM tree — a shadow root starts its own groups). Two `\u003Cdetails name=\"settings\">` elements in completely different sections of the page, with unrelated markup between them, are still one exclusive group.\n\nThe spec allows it but advises against leaning on it: authors \"should keep those related elements together in a containing element,\" because panels that close each other from disparate corners of a page have a relationship that's hard to discover — especially with a screen reader. It's mostly the thing to watch for: reuse a `name` by accident — paste a component, forget to change the group id — and two accordions you meant to be independent start closing each other's panels, and there's no console warning telling you why.\n\n## Where the JavaScript still earns its keep\n\nNative grouping replaces the *sibling-closing* loop, not everything you might want an accordion to do. You'd still reach for a script if you need to:\n\n- **Open a panel from outside a click** — a \"Contact support\" button that opens the relevant answer still means setting `.open = true` yourself (the group then closes the others). Plain anchor links are the exception: in current browsers, following a `#id` that points at content *inside* a closed `\u003Cdetails>` expands it natively, and the `name` group closes whichever panel was open.\n- **Persist state** — remembering which panel was open across a reload is your `localStorage` write, same as any other piece of UI state.\n- **React to which one opened** — analytics on \"which FAQ gets clicked most\" still listens for the `toggle` event; check `event.newState === \"open\"`, because the sibling the browser auto-closes fires its own `toggle` too (with `newState: \"closed\"`).\n\nNone of that is the accordion's core behavior, though — it's things you'd bolt onto *any* accordion, native or not. The mutual-exclusivity plumbing, the part that used to be your bug to maintain, is gone.\n\nTry both versions side by side below: the naive JS-loop accordion and the `name`-grouped native one, with a toggle to break the `name` value and watch two \"independent\" groups start fighting over the same state.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdetails-name-exclusive-accordion\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n## The lesson that generalizes past accordions\n\n`\u003Cdetails>` picked up `name` grouping the same way `\u003Cdialog>` picked up native modal semantics and `\u003Cinput type=\"date\">` picked up a whole calendar widget: the platform absorbing a pattern that used to be userland plumbing. The tell that it's worth checking MDN before you write the loop is exactly this shape of problem — \"state that needs to stay consistent across a group of elements\" — because that's precisely the kind of thing HTML has been quietly annexing from JavaScript for a few years now.\n\nNext time you're about to write a `forEach` that closes siblings, checks a `data-` attribute, or manages \"only one of these is open at a time,\" it's worth thirty seconds on MDN before the twentieth line of the script. Sometimes the browser already shipped it.\n\nWhat's the last bit of state-management JavaScript you wrote that turned out to already be a native HTML attribute? I've got a second one of these for `popover`'s `popovertarget` — tell me yours first.\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 7-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdetails-name-exclusive-accordion\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\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- [Stop Using outline: none. Use :focus-visible Instead.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-focus-visible-keyboard-focus-rings)\n- [You built your modal with a `\u003Cdiv>` and a focus trap library. The native `\u003Cdialog>` does all of that.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdialog-element-native-modal)\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":47,"canonical":225,"description":49},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fdetails-name-exclusive-accordion","01a0ec73-289b-72dc-b408-ceb5f34cadfb",{"id":228,"locked":18},"01a0ec73-28cb-7355-9e7d-48764849411c",[230],{"id":231,"slug":46,"title":232,"_count":233},"01a0ec73-28e1-74cf-85ab-6b161a962d6d","Native exclusive accordions with \u003Cdetails name>",{"questions":234},7,[236],{"locale":13,"slug":46},{"id":231,"slug":46,"title":232,"_count":238,"questionCount":234},{"questions":234},[240,242,246,250,254,256,260,264,267,271,274,276],{"slug":70,"name":71,"articles":241},122,{"slug":243,"name":244,"articles":245},"javascript","Javascript",101,{"slug":247,"name":248,"articles":249},"frontend","Frontend",78,{"slug":251,"name":252,"articles":253},"tutorial","Tutorial",47,{"slug":67,"name":68,"articles":255},40,{"slug":257,"name":258,"articles":259},"typescript","Typescript",18,{"slug":261,"name":262,"articles":263},"react","React",15,{"slug":265,"name":266,"articles":263},"performance","Performance",{"slug":268,"name":269,"articles":270},"node","Node",11,{"slug":272,"name":273,"articles":270},"browser","Browser",{"slug":61,"name":65,"articles":275},9,{"slug":73,"name":74,"articles":277},8,{"items":279,"meta":403},[280,292,311,331,349,367,385],{"id":45,"slug":46,"title":47,"subtitle":48,"excerpt":49,"coverUrl":50,"locale":13,"readingMinutes":51,"publishedAt":52,"viewCount":281,"likeCount":19,"commentCount":19,"author":282,"vertical":283,"topic":284,"tags":285,"_count":290,"playground":291,"hasQuiz":17,"hasPlayground":17},34,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[286,287,288,289],{"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},{"id":293,"slug":294,"title":295,"subtitle":48,"excerpt":296,"coverUrl":297,"locale":13,"readingMinutes":51,"publishedAt":298,"viewCount":299,"likeCount":19,"commentCount":19,"author":300,"vertical":301,"topic":302,"tags":304,"_count":309,"playground":310,"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",213,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":243,"name":303},"JavaScript",[305,306,307,308],{"slug":243,"name":244,"color":48},{"slug":70,"name":71,"color":48},{"slug":251,"name":252,"color":48},{"slug":61,"name":65,"color":48},{"assessments":76},{"slug":294},{"id":312,"slug":313,"title":314,"subtitle":48,"excerpt":315,"coverUrl":316,"locale":13,"readingMinutes":317,"publishedAt":318,"viewCount":319,"likeCount":19,"commentCount":19,"author":320,"vertical":321,"topic":322,"tags":324,"_count":329,"playground":330,"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",5,"2026-09-22T19:36:39.450Z",328,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":67,"name":323},"CSS",[325,326,327,328],{"slug":67,"name":68,"color":48},{"slug":61,"name":65,"color":48},{"slug":70,"name":71,"color":48},{"slug":73,"name":74,"color":48},{"assessments":76},{"slug":313},{"id":332,"slug":333,"title":334,"subtitle":48,"excerpt":335,"coverUrl":336,"locale":13,"readingMinutes":51,"publishedAt":337,"viewCount":338,"likeCount":19,"commentCount":19,"author":339,"vertical":340,"topic":341,"tags":342,"_count":347,"playground":348,"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",270,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":243,"name":303},[343,344,345,346],{"slug":243,"name":244,"color":48},{"slug":70,"name":71,"color":48},{"slug":61,"name":65,"color":48},{"slug":251,"name":252,"color":48},{"assessments":76},{"slug":333},{"id":350,"slug":351,"title":352,"subtitle":48,"excerpt":353,"coverUrl":354,"locale":13,"readingMinutes":317,"publishedAt":355,"viewCount":356,"likeCount":19,"commentCount":19,"author":357,"vertical":358,"topic":359,"tags":360,"_count":365,"playground":366,"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",352,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":243,"name":303},[361,362,363,364],{"slug":70,"name":71,"color":48},{"slug":243,"name":244,"color":48},{"slug":61,"name":65,"color":48},{"slug":247,"name":248,"color":48},{"assessments":76},{"slug":351},{"id":368,"slug":369,"title":370,"subtitle":48,"excerpt":371,"coverUrl":372,"locale":13,"readingMinutes":51,"publishedAt":373,"viewCount":374,"likeCount":19,"commentCount":19,"author":375,"vertical":376,"topic":377,"tags":378,"_count":383,"playground":384,"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",398,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[379,380,381,382],{"slug":61,"name":65,"color":48},{"slug":73,"name":74,"color":48},{"slug":70,"name":71,"color":48},{"slug":247,"name":248,"color":48},{"assessments":76},{"slug":369},{"id":386,"slug":387,"title":388,"subtitle":48,"excerpt":389,"coverUrl":390,"locale":13,"readingMinutes":317,"publishedAt":391,"viewCount":392,"likeCount":19,"commentCount":19,"author":393,"vertical":394,"topic":395,"tags":396,"_count":401,"playground":402,"hasQuiz":17,"hasPlayground":17},"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.","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","2026-08-08T07:00:10.810Z",511,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[397,398,399,400],{"slug":61,"name":65,"color":48},{"slug":70,"name":71,"color":48},{"slug":247,"name":248,"color":48},{"slug":243,"name":244,"color":48},{"assessments":76},{"slug":387},{"page":76,"perPage":234,"total":275,"totalPages":31},"\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\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> items \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">querySelectorAll\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"details.faq-item\"\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\nitems\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">forEach\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>item\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  item\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"toggle\"\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>\u003Cspan class=\"shj-oper\">!\u003C\u002Fspan>item\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>open\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">return\u003C\u002Fspan>;\n    items\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">forEach\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>other\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>other \u003Cspan class=\"shj-oper\">!==\u003C\u002Fspan> item\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> other\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>open \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bool\">false\u003C\u002Fspan>;\n    \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>;\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>\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>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-var\">details\u003C\u002Fspan> \u003Cspan class=\"shj-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"faq\"\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\">summary\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>What's your refund policy?\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">summary\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>Full refund within 30 days, no questions asked.\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;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">details\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\">details\u003C\u002Fspan> \u003Cspan class=\"shj-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"faq\"\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\">summary\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Do you offer team plans?\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">summary\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>Yes — see the pricing page for per-seat rates.\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;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">details\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\">details\u003C\u002Fspan> \u003Cspan class=\"shj-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-str\">\"faq\"\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\">summary\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>Can I cancel anytime?\u003Cspan class=\"shj-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">summary\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>Yes, from account settings, effective end of billing period.\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;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-var\">details\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>",{"locked":18,"total":19,"comments":407},[]]