Tabs Simple
Tabs
GSAP
JS
CMS
Preview Links
Custom JS
Enable custom code in preview or view on published site.
Enable custom code?
Last Updated: Nov 8, 2025
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".tab-1_component").forEach((component, componentIndex) => {
if (component.hasAttribute("data-tab-1")) return;
component.setAttribute("data-tab-1", "");
const allowLoop = true,
buttonList = component.querySelector(".tab-1_button_list"),
buttons = component.querySelectorAll(".tab-1_button_item"),
panels = component.querySelectorAll(".tab-1_content_item"),
prevButton = component.querySelector(".tab-1_control_button.is-previous"),
nextButton = component.querySelector(".tab-1_control_button.is-next");
if (!buttonList || !buttons.length || !panels.length) return;
component.querySelector(".tab-1_content_list")?.removeAttribute("role");
buttonList.setAttribute("role", "tablist");
buttons.forEach((el) => el.setAttribute("role", "tab"));
panels.forEach((el) => (el.setAttribute("role", "tabpanel"), el.style.display = "none"));
let activeIndex = -1;
function makeActive(index, animate = true) {
if (activeIndex === index) return;
buttons.forEach((btn, i) => {
btn.classList.toggle("is-active", i === index);
btn.setAttribute("aria-selected", i === index);
btn.setAttribute("tabindex", i === index ? 0 : -1);
});
panels.forEach((el, i) => el.classList.toggle("is-active", i === index));
buttonList.scrollTo({ left: buttons[index].offsetLeft, behavior: "smooth" });
const prevPanel = panels[activeIndex];
const nextPanel = panels[index];
let tl = gsap.timeline({ defaults: { duration: 0.3 } });
if (prevPanel) tl.to(prevPanel, { opacity: 0 });
if (prevPanel) tl.set(prevPanel, { display: "none" });
tl.set(nextPanel, { display: "block" });
tl.fromTo(nextPanel, { opacity: 0 }, { opacity: 1 });
if (!animate) tl.progress(1).kill();
activeIndex = index;
if (typeof ScrollTrigger !== "undefined") ScrollTrigger.refresh();
if (nextButton) nextButton.disabled = index === buttons.length - 1 && !allowLoop;
if (prevButton) prevButton.disabled = index === 0 && !allowLoop;
if (animate) buttons[index].focus();
};
makeActive(0, false);
const updateIndex = (delta) => makeActive((activeIndex + delta + buttons.length) % buttons.length);
nextButton?.addEventListener("click", () => updateIndex(1));
prevButton?.addEventListener("click", () => updateIndex(-1));
buttons.forEach((btn, index) => {
btn.id = `tab-1-button-${componentIndex}-${index}`;
btn.setAttribute("aria-controls", `tab-1-panel-${componentIndex}-${index}`);
panels[index].id = `tab-1-panel-${componentIndex}-${index}`;
panels[index].setAttribute("aria-labelledby", btn.id);
btn.addEventListener("click", () => makeActive(index));
btn.addEventListener("keydown", (e) => {
if (["ArrowRight", "ArrowDown"].includes(e.key)) updateIndex(1);
else if (["ArrowLeft", "ArrowUp"].includes(e.key)) updateIndex(-1);
});
});
});
});
</script>