Open demo

CSS code

HTML
<div class="grid">
<div><span class="lbl">details and summary</span>
<div class="faq">
<details open><summary>How long does delivery take?</summary><p>Orders placed before 2pm leave the same day and arrive in two to three working days.</p></details>
<details><summary>Can I return a sale item?</summary><p>Yes, within 30 days, as long as the tags are still attached.</p></details>
<details><summary>Do you ship outside the EU?</summary><p>We ship to the UK, Norway and Switzerland. Duties are shown at checkout.</p></details>
</div></div>
<div><span class="lbl">Accordion with a custom arrow</span>
<div class="acc">
<h3><button type="button" class="acc-btn" aria-expanded="true" aria-controls="acc-1" data-disclosure>Which plan suits a team of five?<span class="chev" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="acc-panel" id="acc-1">Team, at 9 euros a seat. It adds shared folders and an admin view of who can see what.</div>
<h3><button type="button" class="acc-btn" aria-expanded="false" aria-controls="acc-2" data-disclosure>Is there a discount for charities?<span class="chev" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="acc-panel" id="acc-2" hidden>Registered charities get 50 percent off any plan. Send us your registration number.</div>
<h3><button type="button" class="acc-btn" aria-expanded="false" aria-controls="acc-3" data-disclosure>What happens when a trial ends?<span class="chev" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="acc-panel" id="acc-3" hidden>Your files stay put and become read-only until you choose a plan.</div>
</div></div>
<div class="sel-field"><span class="lbl">Select with a custom arrow</span>
<label for="sel-size">Shoe size (EU)</label>
<select class="sel" id="sel-size"><option>39</option><option>40</option><option selected>41</option><option>42</option><option>43</option></select>
</div>
<div class="tall"><span class="lbl">Dropdown chevron</span>
<div class="dd">
<button type="button" class="dd-btn" aria-expanded="true" aria-controls="dd-sort" data-disclosure><span>Sort:</span> Newest first<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg></button>
<ul class="dd-menu" id="dd-sort">
<li><a href="#" aria-current="true">Newest first</a></li>
<li><a href="#">Price, low to high</a></li>
<li><a href="#">Price, high to low</a></li>
<li><a href="#">Best rated</a></li>
</ul></div></div>
</div>
CSS
/* Chevrons that follow state. The rotation is driven by [open] on <details> and by aria-expanded on buttons,
   so the arrow can never disagree with what assistive technology announces. */
.faq,.acc,.dd,.sel-field{--ink:#17142b;--accent:#4232d8;--tint:#efedfd;--line:#e4e2ef;--muted:#4a4660}
/* 1. details / summary with a border chevron */
.faq{background:#fff;border:1px solid var(--line);border-radius:14px}
.faq details+details{border-top:1px solid var(--line)}
.faq summary{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border-radius:13px;
  list-style:none;cursor:pointer;font-size:.95rem;font-weight:650;color:var(--ink)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"";flex:none;width:9px;height:9px;margin:-5px 4px 0 0;border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  rotate:45deg;transition:rotate .25s,margin .25s}
.faq details[open] summary::after{rotate:225deg;margin-top:5px}
.faq summary:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.faq p{padding:0 18px 16px;font-size:.88rem;line-height:1.6;color:var(--muted)}
/* 2. Accordion with a chevron in a circle */
.acc{background:#fff;border:1px solid var(--line);border-radius:14px}
.acc h3{font-size:inherit}
.acc h3+div+h3{border-top:1px solid var(--line)}
.acc-btn{display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;padding:14px 16px 14px 18px;border:0;border-radius:13px;
  background:none;color:var(--ink);font:inherit;font-size:.95rem;font-weight:650;text-align:left;cursor:pointer}
.acc-btn:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.acc-btn .chev{display:grid;place-items:center;flex:none;width:28px;height:28px;border-radius:50%;background:var(--tint);color:var(--accent);
  transition:rotate .3s,background-color .3s,color .3s}
.acc-btn[aria-expanded="true"] .chev{rotate:180deg;background:var(--accent);color:#fff}
.acc-panel{padding:0 18px 16px;font-size:.88rem;line-height:1.6;color:var(--muted)}
/* 3. Dropdown button whose chevron flips */
.dd{position:relative;display:inline-block}
.dd-btn{display:inline-flex;align-items:center;gap:10px;padding:10px 14px 10px 16px;border:1px solid #8e89a8;border-radius:10px;background:#fff;
  color:var(--ink);font:inherit;font-size:.9rem;cursor:pointer}
.dd-btn span{color:var(--muted)}
.dd-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.dd-btn[aria-expanded="true"]{border-color:var(--accent)}
.dd-btn[aria-expanded="true"] svg{rotate:180deg}
.dd-menu{position:absolute;top:calc(100% + 6px);left:0;z-index:5;min-width:230px;margin:0;padding:6px;list-style:none;background:#fff;
  border:1px solid var(--line);border-radius:12px;box-shadow:0 14px 30px -12px rgba(23,20,43,.3)}
.dd-menu[hidden]{display:none}
.dd-menu a{display:block;padding:9px 12px;border-radius:8px;color:var(--ink);font-size:.88rem;text-decoration:none}
.dd-menu a:hover{background:var(--tint)}
.dd-menu a[aria-current]{color:var(--accent);font-weight:650}
.dd-menu a:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.acc svg,.dd svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.dd svg{transition:rotate .25s}
/* 4. Native select with a custom arrow */
.sel-field label{display:block;margin-bottom:6px;font-size:.85rem;font-weight:650;color:var(--ink)}
.sel{width:100%;max-width:320px;padding:10px 42px 10px 14px;border:1px solid #8e89a8;border-radius:10px;appearance:none;cursor:pointer;
  background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234232d8' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 14px center/14px;
  color:var(--ink);font:inherit;font-size:.9rem}
.sel:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.faq summary::after,.acc-btn .chev,.dd svg{transition:none}}
JavaScript
// Toggle any [data-disclosure] button: flip aria-expanded and show or hide the element it controls.
// Escape closes an open dropdown and returns focus to its button.
document.querySelectorAll('[data-disclosure]').forEach(btn => {
  const panel = document.getElementById(btn.getAttribute('aria-controls'));
  const set = open => { btn.setAttribute('aria-expanded', open); panel.hidden = !open; };
  btn.addEventListener('click', () => set(btn.getAttribute('aria-expanded') !== 'true'));
  if (btn.closest('.dd')) btn.closest('.dd').addEventListener('keydown', e => {
    if (e.key === 'Escape' && !panel.hidden) { set(false); btn.focus(); }
  });
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS, Bootstrap 5.3.8 JS bundle

HTML
<div class="chev-ui row row-cols-1 row-cols-md-2 gx-4 gy-5 align-items-start">
<div class="col"><span class="lbl">details and summary</span>
<div class="faq list-group">
<details class="list-group-item p-0" open><summary>How long does delivery take?</summary><p class="mb-0">Orders placed before 2pm leave the same day and arrive in two to three working days.</p></details>
<details class="list-group-item p-0"><summary>Can I return a sale item?</summary><p class="mb-0">Yes, within 30 days, as long as the tags are still attached.</p></details>
<details class="list-group-item p-0"><summary>Do you ship outside the EU?</summary><p class="mb-0">We ship to the UK, Norway and Switzerland. Duties are shown at checkout.</p></details>
</div></div>
<div class="col"><span class="lbl">Accordion with a custom arrow</span>
<div class="acc accordion" id="acc">
<div class="accordion-item"><h3 class="accordion-header"><button type="button" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#acc-1" aria-expanded="true" aria-controls="acc-1">Which plan suits a team of five?</button></h3>
<div class="accordion-collapse collapse show" id="acc-1" data-bs-parent="#acc"><div class="accordion-body">Team, at 9 euros a seat. It adds shared folders and an admin view of who can see what.</div></div></div>
<div class="accordion-item"><h3 class="accordion-header"><button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#acc-2" aria-expanded="false" aria-controls="acc-2">Is there a discount for charities?</button></h3>
<div class="accordion-collapse collapse" id="acc-2" data-bs-parent="#acc"><div class="accordion-body">Registered charities get 50 percent off any plan. Send us your registration number.</div></div></div>
<div class="accordion-item"><h3 class="accordion-header"><button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#acc-3" aria-expanded="false" aria-controls="acc-3">What happens when a trial ends?</button></h3>
<div class="accordion-collapse collapse" id="acc-3" data-bs-parent="#acc"><div class="accordion-body">Your files stay put and become read-only until you choose a plan.</div></div></div>
</div></div>
<div class="col"><span class="lbl">Select with a custom arrow</span>
<label for="sel-size" class="form-label mb-1 fw-semibold small text-body-emphasis">Shoe size (EU)</label>
<select class="sel form-select" id="sel-size"><option>39</option><option>40</option><option selected>41</option><option>42</option><option>43</option></select>
</div>
<div class="col tall"><span class="lbl">Dropdown chevron</span>
<div class="dropdown d-inline-block">
<button type="button" class="dd-btn btn dropdown-toggle d-inline-flex align-items-center gap-2 show" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="true"><span>Sort:</span> Newest first<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg></button>
<ul class="dd-menu dropdown-menu show">
<li><a class="dropdown-item active" href="#" aria-current="true">Newest first</a></li>
<li><a class="dropdown-item" href="#">Price, low to high</a></li>
<li><a class="dropdown-item" href="#">Price, high to low</a></li>
<li><a class="dropdown-item" href="#">Best rated</a></li>
</ul></div></div>
</div>
CSS
/* Bootstrap .accordion, .dropdown and .form-select with custom arrows, plus a <details> list on .list-group.
   The accordion arrow is swapped through --bs-accordion-btn-icon / -active-icon; Bootstrap rotates it when the item opens. */
.chev-ui{--ink:#17142b;--accent:#4232d8;--tint:#efedfd;--line:#e4e2ef;--muted:#4a4660}
/* 1. details / summary with a border chevron */
.faq{--bs-list-group-border-color:var(--line);--bs-list-group-border-radius:14px}
.faq summary{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border-radius:13px;
  list-style:none;cursor:pointer;font-size:.95rem;font-weight:650;color:var(--ink)}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"";flex:none;width:9px;height:9px;margin:-5px 4px 0 0;border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  rotate:45deg;transition:rotate .25s,margin .25s}
.faq details[open] summary::after{rotate:225deg;margin-top:5px}
.faq summary:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.faq p{padding:0 18px 16px;font-size:.88rem;line-height:1.6;color:var(--muted)}
/* 2. Bootstrap accordion with a chevron in a circle */
.acc{--bs-accordion-border-color:var(--line);--bs-accordion-border-radius:14px;--bs-accordion-inner-border-radius:13px;
  --bs-accordion-btn-padding-x:18px;--bs-accordion-btn-padding-y:14px;--bs-accordion-btn-color:var(--ink);--bs-accordion-active-color:var(--ink);
  --bs-accordion-active-bg:#fff;--bs-accordion-btn-focus-box-shadow:none;--bs-accordion-btn-icon-width:28px;--bs-accordion-btn-icon-transform:rotate(180deg);
  --bs-accordion-btn-icon-transition:transform .3s;--bs-accordion-body-padding-x:18px;--bs-accordion-body-padding-y:0;
  --bs-accordion-btn-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Ccircle cx='14' cy='14' r='14' fill='%23efedfd'/%3E%3Cpath d='M9.5 12l4.5 4.5 4.5-4.5' fill='none' stroke='%234232d8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --bs-accordion-btn-active-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Ccircle cx='14' cy='14' r='14' fill='%234232d8'/%3E%3Cpath d='M9.5 12l4.5 4.5 4.5-4.5' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.acc .accordion-button{gap:16px;padding-right:16px;font-size:.95rem;font-weight:650;box-shadow:none}
.acc .accordion-button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.acc .accordion-body{padding-bottom:16px;font-size:.88rem;line-height:1.6;color:var(--muted)}
/* 3. Bootstrap dropdown whose chevron flips */
.dd-btn{--bs-btn-color:var(--ink);--bs-btn-bg:#fff;--bs-btn-border-color:#8e89a8;--bs-btn-hover-color:var(--ink);--bs-btn-hover-bg:#fff;
  --bs-btn-hover-border-color:var(--accent);--bs-btn-active-color:var(--ink);--bs-btn-active-bg:#fff;--bs-btn-active-border-color:var(--accent);
  --bs-btn-border-radius:10px;padding:10px 14px 10px 16px;font-size:.9rem}
.dd-btn::after{display:none}
.dd-btn span{color:var(--muted)}
.dd-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px;box-shadow:none}
.dd-btn svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;transition:rotate .25s}
.dd-btn[aria-expanded="true"] svg{rotate:180deg}
.dd-menu{--bs-dropdown-min-width:230px;--bs-dropdown-padding-x:6px;--bs-dropdown-padding-y:6px;--bs-dropdown-border-color:var(--line);
  --bs-dropdown-border-radius:12px;--bs-dropdown-spacer:6px;--bs-dropdown-font-size:.88rem;--bs-dropdown-link-color:var(--ink);
  --bs-dropdown-link-hover-bg:var(--tint);--bs-dropdown-link-active-color:var(--accent);--bs-dropdown-link-active-bg:transparent;
  --bs-dropdown-item-padding-x:12px;--bs-dropdown-item-padding-y:9px;--bs-dropdown-item-border-radius:8px;
  box-shadow:0 14px 30px -12px rgba(23,20,43,.3)}
.dd-menu .dropdown-item.active{font-weight:650}
.dd-menu .dropdown-item:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* 4. .form-select with a custom arrow */
.sel{--bs-form-select-bg-img:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234232d8' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  max-width:320px;padding:10px 42px 10px 14px;border-color:#8e89a8;border-radius:10px;background-position:right 14px center;background-size:14px;
  color:var(--ink);font-size:.9rem;cursor:pointer}
.sel:focus{border-color:#8e89a8;box-shadow:none}
.sel:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.faq summary::after,.acc .accordion-button::after,.acc .collapsing,.dd-btn svg{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="grid grid-cols-1 items-start gap-x-6 gap-y-10 md:grid-cols-2">
<div><span class="mb-3.5 block text-[.72rem] tracking-[.12em] text-[#5d5a72] uppercase">details and summary</span>
<div class="rounded-[14px] border border-line bg-white">
<details class="group" open><summary class="flex cursor-pointer list-none items-center justify-between gap-4 rounded-[13px] px-[18px] py-4 text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent [&::-webkit-details-marker]:hidden after:-mt-[5px] after:mr-1 after:size-[9px] after:flex-none after:rotate-45 after:border-r-2 after:border-b-2 after:border-accent after:transition-[rotate,margin] after:duration-[250ms] after:content-[''] group-open:after:mt-[5px] group-open:after:rotate-[225deg] motion-reduce:after:transition-none">How long does delivery take?</summary><p class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted">Orders placed before 2pm leave the same day and arrive in two to three working days.</p></details>
<details class="group border-t border-line"><summary class="flex cursor-pointer list-none items-center justify-between gap-4 rounded-[13px] px-[18px] py-4 text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent [&::-webkit-details-marker]:hidden after:-mt-[5px] after:mr-1 after:size-[9px] after:flex-none after:rotate-45 after:border-r-2 after:border-b-2 after:border-accent after:transition-[rotate,margin] after:duration-[250ms] after:content-[''] group-open:after:mt-[5px] group-open:after:rotate-[225deg] motion-reduce:after:transition-none">Can I return a sale item?</summary><p class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted">Yes, within 30 days, as long as the tags are still attached.</p></details>
<details class="group border-t border-line"><summary class="flex cursor-pointer list-none items-center justify-between gap-4 rounded-[13px] px-[18px] py-4 text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent [&::-webkit-details-marker]:hidden after:-mt-[5px] after:mr-1 after:size-[9px] after:flex-none after:rotate-45 after:border-r-2 after:border-b-2 after:border-accent after:transition-[rotate,margin] after:duration-[250ms] after:content-[''] group-open:after:mt-[5px] group-open:after:rotate-[225deg] motion-reduce:after:transition-none">Do you ship outside the EU?</summary><p class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted">We ship to the UK, Norway and Switzerland. Duties are shown at checkout.</p></details>
</div></div>
<div><span class="mb-3.5 block text-[.72rem] tracking-[.12em] text-[#5d5a72] uppercase">Accordion with a custom arrow</span>
<div class="rounded-[14px] border border-line bg-white">
<h3><button type="button" class="group flex w-full cursor-pointer items-center justify-between gap-4 rounded-[13px] py-3.5 pr-4 pl-[18px] text-left text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent" aria-expanded="true" aria-controls="acc-1" data-disclosure>Which plan suits a team of five?<span class="grid size-7 flex-none place-items-center rounded-full bg-tint text-accent transition-[rotate,background-color,color] duration-300 group-aria-expanded:rotate-180 group-aria-expanded:bg-accent group-aria-expanded:text-white motion-reduce:transition-none" aria-hidden="true"><svg viewBox="0 0 24 24" class="size-3.5 fill-none stroke-current stroke-[2.4]" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted" id="acc-1">Team, at 9 euros a seat. It adds shared folders and an admin view of who can see what.</div>
<h3 class="border-t border-line"><button type="button" class="group flex w-full cursor-pointer items-center justify-between gap-4 rounded-[13px] py-3.5 pr-4 pl-[18px] text-left text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent" aria-expanded="false" aria-controls="acc-2" data-disclosure>Is there a discount for charities?<span class="grid size-7 flex-none place-items-center rounded-full bg-tint text-accent transition-[rotate,background-color,color] duration-300 group-aria-expanded:rotate-180 group-aria-expanded:bg-accent group-aria-expanded:text-white motion-reduce:transition-none" aria-hidden="true"><svg viewBox="0 0 24 24" class="size-3.5 fill-none stroke-current stroke-[2.4]" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted" id="acc-2" hidden>Registered charities get 50 percent off any plan. Send us your registration number.</div>
<h3 class="border-t border-line"><button type="button" class="group flex w-full cursor-pointer items-center justify-between gap-4 rounded-[13px] py-3.5 pr-4 pl-[18px] text-left text-[.95rem] font-[650] text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent" aria-expanded="false" aria-controls="acc-3" data-disclosure>What happens when a trial ends?<span class="grid size-7 flex-none place-items-center rounded-full bg-tint text-accent transition-[rotate,background-color,color] duration-300 group-aria-expanded:rotate-180 group-aria-expanded:bg-accent group-aria-expanded:text-white motion-reduce:transition-none" aria-hidden="true"><svg viewBox="0 0 24 24" class="size-3.5 fill-none stroke-current stroke-[2.4]" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg></span></button></h3>
<div class="px-[18px] pb-4 text-[.88rem] leading-[1.6] text-muted" id="acc-3" hidden>Your files stay put and become read-only until you choose a plan.</div>
</div></div>
<div><span class="mb-3.5 block text-[.72rem] tracking-[.12em] text-[#5d5a72] uppercase">Select with a custom arrow</span>
<label for="sel-size" class="mb-1.5 block text-[.85rem] font-[650] text-ink">Shoe size (EU)</label>
<select class="w-full max-w-[320px] cursor-pointer appearance-none rounded-[10px] border border-[#8e89a8] bg-white sel-arrow bg-size-[14px] bg-position-[right_14px_center] bg-no-repeat py-2.5 pr-[42px] pl-3.5 text-[.9rem] text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent" id="sel-size"><option>39</option><option>40</option><option selected>41</option><option>42</option><option>43</option></select>
</div>
<div class="min-h-[220px]"><span class="mb-3.5 block text-[.72rem] tracking-[.12em] text-[#5d5a72] uppercase">Dropdown chevron</span>
<div class="dd relative inline-block">
<button type="button" class="group inline-flex cursor-pointer items-center gap-2.5 rounded-[10px] border border-[#8e89a8] bg-white py-2.5 pr-3.5 pl-4 text-[.9rem] text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent aria-expanded:border-accent" aria-expanded="true" aria-controls="dd-sort" data-disclosure><span class="text-muted">Sort:</span> Newest first<svg viewBox="0 0 24 24" class="size-3.5 fill-none stroke-current stroke-[2.4] transition-[rotate] duration-[250ms] group-aria-expanded:rotate-180 motion-reduce:transition-none" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg></button>
<ul class="absolute top-[calc(100%+6px)] left-0 z-10 min-w-[230px] rounded-xl border border-line bg-white p-1.5 shadow-[0_14px_30px_-12px_rgba(23,20,43,.3)]" id="dd-sort">
<li><a href="#" aria-current="true" class="block rounded-lg px-3 py-[9px] text-[.88rem] font-[650] text-accent hover:bg-tint focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent">Newest first</a></li>
<li><a href="#" class="block rounded-lg px-3 py-[9px] text-[.88rem] text-ink hover:bg-tint focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent">Price, low to high</a></li>
<li><a href="#" class="block rounded-lg px-3 py-[9px] text-[.88rem] text-ink hover:bg-tint focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent">Price, high to low</a></li>
<li><a href="#" class="block rounded-lg px-3 py-[9px] text-[.88rem] text-ink hover:bg-tint focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent">Best rated</a></li>
</ul></div></div>
</div>
CSS
/* Palette and the select arrow. The chevrons rotate with group-open: (details) and group-aria-expanded: (buttons). */
@theme {
  --color-ink: #17142b;
  --color-accent: #4232d8;
  --color-tint: #efedfd;
  --color-line: #e4e2ef;
  --color-muted: #4a4660;
}
/* The select's chevron: an inline SVG background. */
@utility sel-arrow{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234232d8' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")}
JavaScript
// Toggle any [data-disclosure] button: flip aria-expanded and show or hide the element it controls.
// Escape closes an open dropdown and returns focus to its button.
document.querySelectorAll('[data-disclosure]').forEach(btn => {
  const panel = document.getElementById(btn.getAttribute('aria-controls'));
  const set = open => { btn.setAttribute('aria-expanded', open); panel.hidden = !open; };
  btn.addEventListener('click', () => set(btn.getAttribute('aria-expanded') !== 'true'));
  if (btn.closest('.dd')) btn.closest('.dd').addEventListener('keydown', e => {
    if (e.key === 'Escape' && !panel.hidden) { set(false); btn.focus(); }
  });
});

About this set

Chevrons that turn with the state of the control they belong to, the arrows behind accordions, FAQs, dropdowns and selects. The details and summary FAQ draws a border chevron with summary::after and turns it when the details element has the open attribute, so it works with no script. The accordion with a custom arrow puts the chevron in a tinted circle that rotates and fills when its button has aria-expanded=”true”. In the Bootstrap file this is a real Bootstrap .accordion, with the arrow swapped through –bs-accordion-btn-icon and –bs-accordion-btn-active-icon, which is the usual way to give a Bootstrap accordion a custom arrow. The dropdown chevron flips when its sort menu opens; in Bootstrap it is a .dropdown with the default caret hidden. The select keeps the native element and replaces only its arrow with an inline SVG background. Because every rotation is keyed to [open] or aria-expanded rather than a separate class, the arrow cannot disagree with what assistive technology announces. The plain and Tailwind accordion and dropdown use a few lines of JavaScript that flip aria-expanded and the hidden attribute; Escape closes the dropdown.

What’s included

  • details and summary FAQ with no JavaScript
  • Accordion arrow driven by aria-expanded
  • Bootstrap .accordion with a custom arrow through --bs-accordion-btn-icon
  • Dropdown chevron that flips, with Escape to close
  • Native select with a custom SVG arrow

Accessibility

The FAQ uses native details and summary. The accordion and dropdown buttons carry aria-expanded and aria-controls, and the chevron rotation is driven by that attribute, so the visual state and the announced state always match. The dropdown closes on Escape and returns focus to its button, and the current sort option has aria-current. The select has a visible label. Every control shows a 2px indigo focus outline, and rotations are instant under prefers-reduced-motion.

Customise it

Set --accent, --tint, --line, --ink and --muted on .faq, .acc, .dd and .sel-field. In Bootstrap edit the --bs-accordion-*, --bs-dropdown-* and --bs-form-select-bg-img variables; in Tailwind edit the @theme colours and the sel-arrow utility.