Skip to content

Instantly share code, notes, and snippets.

@steiha
Last active February 4, 2025 18:51
Show Gist options
  • Save steiha/7f4c4c7434d2e8dcf90b56423e5fbaa4 to your computer and use it in GitHub Desktop.
Save steiha/7f4c4c7434d2e8dcf90b56423e5fbaa4 to your computer and use it in GitHub Desktop.
Persisting Bootstrap accordion UI state in the local browser storage
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>
Persisting Bootstrap accordion UI state in the local browser storage
</title>
<meta
content="width=device-width, initial-scale=1.0, maximum-scale=4.0, minimum-scale=.25, user-scalable=1, shrink-to-fit=no"
name="viewport"
/>
<script
src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
crossorigin="anonymous"
></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"
></script>
</head>
<body>
<h1>
Persisting Bootstrap accordion UI state in the local browser storage
</h1>
<div class="accordion" id="accordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseOne"
aria-expanded="false"
aria-controls="collapseOne"
>
Accordion Item #1
</button>
</h2>
<div
id="collapseOne"
class="accordion-collapse collapse"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong> It is
hidden by default, until the collapse plugin adds the appropriate
classes that we use to style each element. These classes control the
overall appearance, as well as the showing and hiding via CSS
transitions. You can modify any of this with custom CSS or
overriding our default variables. It's also worth noting that just
about any HTML can go within the <code>.accordion-body</code>,
though the transition does limit overflow.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseTwo"
aria-expanded="false"
aria-controls="collapseTwo"
>
Accordion Item #2
</button>
</h2>
<div
id="collapseTwo"
class="accordion-collapse collapse"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<strong>This is the second item's accordion body.</strong> It is
hidden by default, until the collapse plugin adds the appropriate
classes that we use to style each element. These classes control the
overall appearance, as well as the showing and hiding via CSS
transitions. You can modify any of this with custom CSS or
overriding our default variables. It's also worth noting that just
about any HTML can go within the <code>.accordion-body</code>,
though the transition does limit overflow.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseThree"
aria-expanded="false"
aria-controls="collapseThree"
>
Accordion Item #3
</button>
</h2>
<div
id="collapseThree"
class="accordion-collapse collapse"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<strong>This is the third item's accordion body.</strong> It is
hidden by default, until the collapse plugin adds the appropriate
classes that we use to style each element. These classes control the
overall appearance, as well as the showing and hiding via CSS
transitions. You can modify any of this with custom CSS or
overriding our default variables. It's also worth noting that just
about any HTML can go within the <code>.accordion-body</code>,
though the transition does limit overflow.
</div>
</div>
</div>
</div>
<div class="btn-group my-5">
<a href="?" class="btn btn-lg btn-primary">reload page</a>
<a href="#" class="btn btn-lg btn-secondary" id="resetData"
>reset storage</a
>
</div>
<style>
body {
background: #ccc;
padding: 5rem;
}
#accordion * {
transition: none;
}
</style>
<script>
function saveSetIntoStorage(storageKey, payload) {
localStorage.setItem(storageKey, JSON.stringify(Array.from(payload)));
}
function loadSetFromStorage(storageKey) {
return localStorage.getItem(storageKey) === null
? new Set()
: new Set(JSON.parse(localStorage.getItem(storageKey)));
}
function removeSetFromStorage(storageKey) {
localStorage.removeItem(storageKey);
}
function restoreAccordionPanels(storageKey, accordionId) {
let activeItemSet = loadSetFromStorage(storageKey);
for (const activeItem of activeItemSet) {
let element = document.querySelector("#" + activeItem);
bootstrap.Collapse.getOrCreateInstance(element).show();
console.log("now show " + activeItem);
}
}
function toggleAccordionPanelState(storageKey, item) {
let storageDataSet = loadSetFromStorage(storageKey);
if (storageDataSet.has(item)) {
console.log("delete " + item);
storageDataSet.delete(item);
} else {
console.log("add " + item);
storageDataSet.add(item);
}
console.log(Array.from(storageDataSet));
saveSetIntoStorage(storageKey, storageDataSet);
}
$(function () {
restoreAccordionPanels("accordion-activePanels", "#accordion");
$("#resetData").on("click", function () {
removeSetFromStorage("accordion-activePanels");
window.location.replace("?");
});
$("#accordion").on("show.bs.collapse hide.bs.collapse", function (e) {
toggleAccordionPanelState("accordion-activePanels", e.target.id);
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment