Component
Single Open Accordion
Generic accordion enforcing one-open-at-a-time behavior with an expanding accent bar and a live open-count announcement. For terms, policies, and focused help centers.
- Component
- Tailwind
- HTML
- MIT
Preview
Live component
9:41 100%
devsnips.dev/library/tailwind/components/accordions/single-open-accordion/ fluid · no fixed width 100%
Install
Add to your project
npx devsnips add Tailwind/Components/Accordions/single-open-accordion Tailwind/Components/Accordions/single-open-accordion <!--
Snippet Name: Single Open Accordion
Description: Generic accordion enforcing one-open-at-a-time behavior with an expanding accent bar and an open-count chip. Keyboard and aria wired.
Author: DevSnips Contributors
Usage Example: Terms, policies, or help centers where focus should stay on one answer.
-->
<div class="space-y-2" data-accordion="single" data-single-open>
<div class="accordion-item-wrap relative overflow-hidden rounded-xl border border-gray-200 bg-white transition-colors hover:border-gray-300" data-accordion-item>
<span class="accordion-accent absolute inset-y-0 left-0 w-1 origin-top scale-y-0 bg-emerald-500 transition-transform duration-300 ease-out"></span>
<h3>
<button type="button" id="so-trigger-1" aria-controls="so-panel-1" aria-expanded="false" class="accordion-trigger flex w-full items-center justify-between gap-4 pl-5 pr-4 py-4 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-inset rounded-xl">
<span class="text-sm font-semibold text-gray-900">What data do you collect?</span>
<svg class="accordion-chevron h-5 w-5 shrink-0 text-gray-400 transition-transform duration-300 ease-out" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
</button>
</h3>
<div id="so-panel-1" role="region" aria-labelledby="so-trigger-1" class="accordion-panel grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 ease-out">
<div class="overflow-hidden"><p class="pl-5 pr-4 pb-4 text-sm leading-relaxed text-gray-600">We collect only what's required to run your account: email, workspace metadata, and billing country. We never track behavior across other sites, and analytics are anonymized and opt-out-able from your settings.</p></div>
</div>
</div>
<div class="accordion-item-wrap relative overflow-hidden rounded-xl border border-gray-200 bg-white transition-colors hover:border-gray-300" data-accordion-item>
<span class="accordion-accent absolute inset-y-0 left-0 w-1 origin-top scale-y-0 bg-emerald-500 transition-transform duration-300 ease-out"></span>
<h3>
<button type="button" id="so-trigger-2" aria-controls="so-panel-2" aria-expanded="false" class="accordion-trigger flex w-full items-center justify-between gap-4 pl-5 pr-4 py-4 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-inset rounded-xl">
<span class="text-sm font-semibold text-gray-900">Where is my data stored?</span>
<svg class="accordion-chevron h-5 w-5 shrink-0 text-gray-400 transition-transform duration-300 ease-out" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
</button>
</h3>
<div id="so-panel-2" role="region" aria-labelledby="so-trigger-2" class="accordion-panel grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 ease-out">
<div class="overflow-hidden"><p class="pl-5 pr-4 pb-4 text-sm leading-relaxed text-gray-600">Data is encrypted at rest in the region you select during signup, with replicas confined to that region for residency compliance. You can migrate regions on request without downtime.</p></div>
</div>
</div>
<div class="accordion-item-wrap relative overflow-hidden rounded-xl border border-gray-200 bg-white transition-colors hover:border-gray-300" data-accordion-item>
<span class="accordion-accent absolute inset-y-0 left-0 w-1 origin-top scale-y-0 bg-emerald-500 transition-transform duration-300 ease-out"></span>
<h3>
<button type="button" id="so-trigger-3" aria-controls="so-panel-3" aria-expanded="false" class="accordion-trigger flex w-full items-center justify-between gap-4 pl-5 pr-4 py-4 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-inset rounded-xl">
<span class="text-sm font-semibold text-gray-900">How do I request deletion?</span>
<svg class="accordion-chevron h-5 w-5 shrink-0 text-gray-400 transition-transform duration-300 ease-out" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
</button>
</h3>
<div id="so-panel-3" role="region" aria-labelledby="so-trigger-3" class="accordion-panel grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 ease-out">
<div class="overflow-hidden"><p class="pl-5 pr-4 pb-4 text-sm leading-relaxed text-gray-600">Open Privacy, then Request deletion. We confirm by email and permanently remove personal data within 30 days, including backups. A receipt is generated for your records.</p></div>
</div>
</div>
<p class="px-1 pt-1 text-xs text-gray-400" data-open-count aria-live="polite">0 of 3 open</p>
<script>
(function () {
const root = document.currentScript.closest('[data-accordion]');
if (!root) return;
const counter = root.querySelector('[data-open-count]');
const items = Array.from(root.querySelectorAll('[data-accordion-item]'));
const updateCount = () => {
if (!counter) return;
const n = items.filter((i) => i.querySelector('.accordion-trigger').getAttribute('aria-expanded') === 'true').length;
counter.textContent = n + ' of ' + items.length + ' open';
};
items.forEach((item) => {
const trigger = item.querySelector('.accordion-trigger');
const panel = item.querySelector('.accordion-panel');
const chevron = item.querySelector('.accordion-chevron');
const accent = item.querySelector('.accordion-accent');
if (!trigger || !panel) return;
const close = () => { trigger.setAttribute('aria-expanded','false'); panel.classList.remove('grid-rows-[1fr]'); panel.classList.add('grid-rows-[0fr]'); if (chevron) chevron.style.transform=''; if (accent) accent.style.transform='scaleY(0)'; };
const open = () => { trigger.setAttribute('aria-expanded','true'); panel.classList.add('grid-rows-[1fr]'); panel.classList.remove('grid-rows-[0fr]'); if (chevron) chevron.style.transform='rotate(180deg)'; if (accent) accent.style.transform='scaleY(1)'; };
trigger.addEventListener('click', () => {
const isOpen = trigger.getAttribute('aria-expanded') === 'true';
items.forEach((o) => { if (o !== item) { const t=o.querySelector('.accordion-trigger'); const p=o.querySelector('.accordion-panel'); const c=o.querySelector('.accordion-chevron'); const a=o.querySelector('.accordion-accent'); t.setAttribute('aria-expanded','false'); p.classList.remove('grid-rows-[1fr]'); p.classList.add('grid-rows-[0fr]'); if(c) c.style.transform=''; if(a) a.style.transform='scaleY(0)'; } });
isOpen ? close() : open();
updateCount();
});
});
updateCount();
})();
</script>
</div> # Single Open Accordion
Accordion that allows only one open section at a time.
## Usage
```bash
npx devsnips add Tailwind/Components/Accordions/single-open-accordion
```
Copy from `code.html`.
## File Structure
`code.html` · `preview.html` · `metadata.json` · `README.md` 78 lines UTF-8 · LF · Spaces: 2
Continue browsing