Dropdown Simple
Dropdown
GSAP
JS
JS Library
Preview Links
Custom JS
Enable custom code in preview or view on published site.
Enable custom code?
Last Updated: Feb 1, 2026
- Set data-preview="true" on .dropdown-1_wrap to preview the dropdown as open in designer
- Set the aria-label="Dropdown Text" on the .dropdown-1_toggle_clickable to match the text of the dropdown
- Set data-open-on-hover-in="true" on the .dropdown-1_wrap to open the dropdown on hover in
- Set data-close-on-hover-out="true" on the .dropdown-1_wrap to close the dropdown on hover out
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/gsap.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".dropdown-1_wrap").forEach((component, index) => {
if (component.hasAttribute("data-dropdown-1")) return;
component.setAttribute("data-dropdown-1", "");
const button = component.querySelector(".dropdown-1_toggle_clickable");
const content = component.querySelector(".dropdown-1_content");
const toggle = component.querySelector(".dropdown-1_toggle_wrap");
const helper = component.querySelector(".dropdown-1_helper");
button.setAttribute("id", `dropdown-btn-${index}`);
button.setAttribute("aria-controls", `dropdown-${index}`);
content.setAttribute("id", `dropdown-${index}`);
content.setAttribute("aria-labelledby", `dropdown-btn-${index}`);
const isTouch = window.matchMedia("(hover: none) and (pointer: coarse)").matches;
if (helper && !isTouch) {
function sizeHelper() {
const h = toggle.offsetHeight;
helper.style.height = h + "px";
}
sizeHelper();
new ResizeObserver(sizeHelper).observe(toggle);
function updateClipPath(xPercent, yPercent) {
helper.style.clipPath = `polygon(${xPercent}% ${yPercent}%, 100% 100%, 0% 100%)`;
}
updateClipPath(50, 0);
component.addEventListener("mousemove", (e) => {
const toggleRect = toggle.getBoundingClientRect();
const helperRect = helper.getBoundingClientRect();
if (
e.clientX >= toggleRect.left &&
e.clientX <= toggleRect.right &&
e.clientY >= toggleRect.top &&
e.clientY <= toggleRect.bottom
) {
const x = e.clientX - helperRect.left;
const y = e.clientY - toggleRect.top;
const xPct = Math.round((x / helperRect.width) * 100);
const yPct = Math.round((y / toggleRect.height) * 100);
updateClipPath(xPct, yPct);
}
});
}
function openDropdown() {
button.setAttribute("aria-expanded", "true");
component.classList.add("is-active");
let tl = gsap.timeline({
onComplete: () => { if (typeof ScrollTrigger !== "undefined") ScrollTrigger.refresh(); }
});
tl.set(content, { display: "block" });
tl.fromTo(content, { height: 0 }, { height: "auto", ease: "power1.inOut", duration: 0.4 });
}
function closeDropdown() {
button.setAttribute("aria-expanded", "false");
component.classList.remove("is-active");
let tl = gsap.timeline({
onComplete: () => { if (typeof ScrollTrigger !== "undefined") ScrollTrigger.refresh(); }
});
tl.to(content, { height: 0, ease: "power1.inOut", duration: 0.4 });
tl.set(content, { display: "none" });
}
function isOpen() {
return button.getAttribute("aria-expanded") === "true";
}
button.addEventListener("click", () => {
isOpen() ? closeDropdown() : openDropdown();
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && isOpen()) {
closeDropdown();
button.focus();
}
if ((e.key === "ArrowDown" || e.key === "ArrowUp") && isOpen() && component.contains(document.activeElement)) {
e.preventDefault();
const items = [...content.querySelectorAll("a, button")];
if (!items.length) return;
const currentIndex = items.indexOf(document.activeElement);
let nextIndex = currentIndex === -1
? (e.key === "ArrowDown" ? 0 : items.length - 1)
: (currentIndex + (e.key === "ArrowDown" ? 1 : -1) + items.length) % items.length;
items[nextIndex].focus();
}
});
document.addEventListener("click", (e) => {
if (isOpen() && !component.contains(e.target)) closeDropdown();
});
if (component.getAttribute("data-open-on-hover-in") === "true") {
component.addEventListener("mouseenter", () => { if (!isOpen()) openDropdown(); });
}
if (component.getAttribute("data-close-on-hover-out") === "true") {
component.addEventListener("mouseleave", () => { if (isOpen()) closeDropdown(); });
}
});
});
</script>









