How to Make Animated Drop Down Menu Using Html

Today we Will Learn Creating an Animated Dropdown Menu using HTML, CSS, and JavaScript

Let’s create an animated Dropdown Menu using HTML, CSS, and JavaScript. This project will add an interactive and visually appealing element to your website, enhancing user experience with smooth animations. We’ll use HTML to structure the content, CSS to style and animate the dropdown, and JavaScript to handle the interactivity. Let’s dive into building this Animated Drop down Menu.

HTML:

This HTML code sets up a webpage with a main section containing a dropdown menu. The dropdown includes a button to toggle the menu and a list of options. It also features social media links at the bottom of the page. The structure is designed to support the dropdown functionality and animations, making the menu visually appealing and interactive.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">

    <style>
        @charset "UTF-8";

        * {
            border: 0;
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        :root {
            --hue: 223;
            --bg: hsl(0, 0%, 100%);
            --fg: hsl(var(--hue), 10%, 10%);
            --trans-dur: 0.3s;
            --trans-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
            --trans-ease-out: cubic-bezier(0.33, 1, 0.68, 1);
            font-size: calc(20px + (40 - 20) * (100vw - 280px) / (3840 - 280));
        }

        body,
        button {
            color: var(--fg);
            font: 1em/1.5 "DM Sans", sans-serif;
            transition: background-color var(--trans-dur), color var(--trans-dur);
        }

        body {
            background-color: black;
            display: flex;
            height: 100vh;
        }

        main {
            margin: auto;
            padding: 0.75em 0;
            width: min-content;
            height: 12em;
        }

        .drop {
            --drop-trans-dur: 0.5s;
            --drop-flare-dist: 0;
            border-radius: 0.5em;
            margin: auto;
            padding: 0.25em 0.25em 0 0.25em;
            position: relative;
            min-width: 9em;
        }

        .drop,
        .drop:after {
            background-color: hsl(var(--hue), 10%, 90%);
            transition: background-color var(--trans-dur);
        }

        .drop:before,
        .drop:after {
            content: "";
            position: absolute;
        }

        .drop:before {
            background-image: radial-gradient(100% 100% at 100% 50%, hsla(var(--hue), 90%, 50%, 0.5), hsla(var(--hue), 90%, 50%, 0) 50%);
            display: none;
            right: 0;
            bottom: 100%;
            width: 9em;
            height: 9em;
        }

        .drop:after {
            border-radius: 0.4375em;
            display: block;
            top: 0.125em;
            left: 0.125em;
            width: calc(100% - 0.25em);
            height: calc(100% - 0.25em);
        }

        .drop__btn {
            background-color: white;
            border-radius: 0.375em;
            box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 0);
            cursor: pointer;
            display: flex;
            align-items: center;
            line-height: 1;
            height: 2.5em;
            outline: transparent;
            margin-bottom: 0.25em;
            padding: 0.75em;
            position: relative;
            width: 100%;
            transition: background-color var(--trans-dur), box-shadow calc(var(--trans-dur) / 2) var(--trans-ease-in-out), color var(--drop-trans-dur);
            -webkit-appearance: none;
            appearance: none;
            -webkit-tap-highlight-color: transparent;
            z-index: 1;
        }

        .drop__btn:hover,
        .drop__btn:focus-visible,
        .drop__btn[aria-expanded=true] {
            background-color: hsl(var(--hue), 10%, 95%);
        }

        .drop__btn:focus-visible {
            box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 1);
        }

        .drop__btn:after {
            border-top: 0.375em solid currentColor;
            border-right: 0.375em solid transparent;
            border-left: 0.375em solid transparent;
            content: "";
            display: block;
            margin-inline-start: auto;
            width: 0;
            height: 0;
            transform-origin: 50% 37.5%;
            transition: transform var(--drop-trans-dur) var(--trans-ease-out);
        }

        .drop__btn[aria-expanded=true]:after {
            transform: rotate(0.5turn);
        }

        .drop--collapsing,
        .drop--expanding,
        .drop__items {
            overflow: hidden;
        }

        .drop__items {
            height: 0;
        }

        .drop__items-inner {
            visibility: hidden;
        }

        .drop--collapsing .drop__btn[aria-expanded=true] {
            background-color: white;
        }

        .drop--collapsing .drop__btn[aria-expanded=true]:after {
            transform: rotate(0);
        }

        .drop--expanding:before {
            display: block;
        }

        .drop__items .drop__btn:hover,
        .drop__items .drop__btn:focus-visible {
            background-color: hsl(var(--hue), 10%, 97.5%);
            color: hsla(var(--hue), 90%, 50%);
        }

        .drop__items .drop__btn:focus-visible {
            box-shadow: 0 0 0 0.25em hsla(var(--hue), 90%, 50%, 0);
        }

        .drop__items .drop__btn:after {
            border: 0;
            content: "";
            display: none;
            width: auto;
            height: auto;
            color: #00fffc;
        }

        .drop__items .drop__btn--selected:after {
            display: block;
        }

        .drop__btn[aria-expanded=true]~.drop__items {
            height: auto;
        }

        .drop__btn[aria-expanded=true]~.drop__items .drop__items-inner {
            visibility: visible;
        }

        .drop:has([aria-expanded=true]) {
            height: auto;
        }

        .drop:has([aria-expanded=true]):before {
            transform: translateY(calc(9em + var(--drop-flare-dist)));
            transition: transform var(--drop-trans-dur) linear;
        }

        @media (prefers-color-scheme: dark) {
            :root {
                --bg: hsl(var(--hue), 10%, 10%);
                --fg: hsl(var(--hue), 10%, 90%);
            }

            .drop,
            .drop:after {
                background-color: #181818;
            }

            .drop__btn {
                background-color: hsl(var(--hue), 10%, 10%);
            }

            .drop__btn:hover,
            .drop__btn:focus-visible,
            .drop__btn[aria-expanded=true] {
                background-color: hsl(var(--hue), 10%, 20%);
            }

            .drop__items .drop__btn:hover,
            .drop__items .drop__btn:focus-visible {
                background-color: hsl(var(--hue), 10%, 15%);
                color: hsla(var(--hue), 90%, 70%);
            }

            .drop--collapsing .drop__btn[aria-expanded=true] {
                background-color: hsl(var(--hue), 10%, 10%);
            }
        }

        
        /* -- External Social Link CSS Styles -- */

        #source-link {
            top: 120px;
        }

        #source-link>i {
            color: rgb(94, 106, 210);
        }

        #yt-link {
            top: 65px;
        }

        #yt-link>i {
            color: rgb(219, 31, 106);

        }

        #Fund-link {
            top: 10px;
        }

        #Fund-link>i {
            color: rgb(255, 251, 0);

        }

        .meta-link {
            align-items: center;
            backdrop-filter: blur(3px);
            background-color: rgba(255, 255, 255, 0.05);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 6px;
            box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
            cursor: pointer;
            display: inline-flex;
            gap: 5px;
            left: 10px;
            padding: 10px 20px;
            position: fixed;
            text-decoration: none;
            transition: background-color 600ms, border-color 600ms;
            z-index: 10000;
        }

        .meta-link:hover {
            background-color: rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.2);
        }

        .meta-link>i,
        .meta-link>span {
            height: 20px;
            line-height: 20px;
        }

        .meta-link>span {
            color: white;
            font-family: "Rubik", sans-serif;
            transition: color 600ms;
        }

    </style>
</head>

<body>
    <main>
        <div class="drop" id="dummy">
            <button class="drop__btn" aria-expanded="false" aria-haspopup="true" type="button"></button>
            <div class="drop__items" data-items>
                <div class="drop__items-inner">
                    <button class="drop__btn" type="button" value="html">Html</button>
                    <button class="drop__btn" type="button" value="css">Css</button>
                    <button class="drop__btn" type="button" value="javascript">JavaScript</button>

                </div>
            </div>
        </div>
    </main>

    
      
    <!--Social Liks codings below-->
    <a id="source-link" class="meta-link" href="" target="_blank">
        <i class="fas fa-link"></i>
        <span class="roboto-mono">Join my Telegram</span>
    </a>

    <a id="yt-link" class="meta-link" href=""
        target="_blank">
        <i class="fab fa-youtube"></i>
        <span> Subscribe my channel</span>
    </a>

    <a id="Fund-link" class="meta-link" href=""
        target="_blank">
        <i class="fas fa-dollar-sign"></i>
        <span> </span>
    </a>

    <script>
        "use strict";
        window.addEventListener("DOMContentLoaded", () => {
            const drop = new DropdownMenu("#dummy");
        });
        class DropdownMenu {
            /**
             * @param el 
            */
            constructor(el) {
                var _a, _b, _c;
                this.animations = [];
                this.options = [
                    { name: "html", friendlyName: "Html" },
                    { name: "css", friendlyName: "Css" },
                    { name: "javascript", friendlyName: "JavaScript" }

                ];
                this.selected = "html";
                this.isCollapsing = false;
                this.isExpanding = false;
                this.animActionsCollapse = {
                    onfinish: this.onAnimationFinish.bind(this, false),
                    oncancel: () => { this.isCollapsing = false; }
                };
                this.animActionsExpand = {
                    onfinish: this.onAnimationFinish.bind(this, true),
                    oncancel: () => { this.isExpanding = false; }
                };
                this.el = document.querySelector(el);
                this.menuButton = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector("button");
                this.itemList = (_b = this.el) === null || _b === void 0 ? void 0 : _b.querySelector("[data-items]");
                this.defaultOption();
                document.addEventListener("click", this.outsideToClose.bind(this));
                window.addEventListener("keydown", this.escToClose.bind(this));
                (_c = this.el) === null || _c === void 0 ? void 0 : _c.addEventListener("click", this.toggle.bind(this));
                window.addEventListener("keydown", this.kbdAction.bind(this));
            }
            get transDuration() {
                if (this.el) {
                    const style = getComputedStyle(this.el);
                    const rawDur = style.getPropertyValue("--drop-trans-dur");
                    let dur = rawDur.substring(0, rawDur.indexOf("s"));
                    const mIndex = dur.indexOf("m");
                    if (mIndex > -1) {
                        dur = dur.substring(0, mIndex);
                        return +dur;
                    }
                    return +dur * 1e3;
                }
                return 0;
            }
            defaultOption() {
                var _a;
                const buttonEl = (_a = this.itemList) === null || _a === void 0 ? void 0 : _a.querySelector(`[value="${this.selected}"]`);
                buttonEl === null || buttonEl === void 0 ? void 0 : buttonEl.classList.add("drop__btn--selected");
                if (this.menuButton) {
                    const optionFound = this.options.find(option => option.name === this.selected);
                    this.menuButton.textContent = (optionFound === null || optionFound === void 0 ? void 0 : optionFound.friendlyName) || "";
                }
            }
            /**
              @param e 
             */
            kbdAction(e) {
                var _a;
                const { key } = e;
                const tabOrArrow = key === "Tab" || key === "ArrowUp" || key === "ArrowDown";
                const notAnimating = !this.isExpanding && !this.isCollapsing;
                if (notAnimating && ((_a = this.menuButton) === null || _a === void 0 ? void 0 : _a.ariaExpanded) === "true" && tabOrArrow) {
                    this.navigateOption(e);
                }
            }
            /**
             * @param e Keydown event
             */
            escToClose(e) {
                var _a;
                if (e.key === "Escape" && (!this.isCollapsing && ((_a = this.menuButton) === null || _a === void 0 ? void 0 : _a.ariaExpanded) === "true")) {
                    this.toggle(e);
                }
            }
            /**
             * @param e Click event
             */
            outsideToClose(e) {
                var _a;
                let target = e.target;
                let elFound = false;
                if (!this.isCollapsing && ((_a = this.menuButton) === null || _a === void 0 ? void 0 : _a.ariaExpanded) === "true") {
                    do {
                        target = target.parentElement;
                        if (target === this.el) {
                            elFound = true;
                        }
                    } while (target);
                    if (!elFound) {
                        this.toggle(e);
                    }
                }
            }
            /**
             * @param e Keydown event
             */
            navigateOption(e) {
                var _a;
                const itemList = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector("[data-items]");
                const buttonEls = itemList === null || itemList === void 0 ? void 0 : itemList.querySelectorAll("button");
                const buttons = Array.from(buttonEls || []);
                const buttonsTemp = [...buttons];
                const first = buttonsTemp.shift();
                const last = buttonsTemp.pop();
                const currentItem = document.activeElement;
                const { key, shiftKey } = e;
                const downKey = key === "ArrowDown";
                const upKey = key === "ArrowUp";
                const currentIndex = buttons.indexOf(currentItem);
                if (!buttons.length) {
                    e.preventDefault();
                }
                else if (downKey) {
                    e.preventDefault();
                    const nextIndex = currentIndex + 1;
                    if (nextIndex >= buttons.length) {
                        first === null || first === void 0 ? void 0 : first.focus();
                        return;
                    }
                    buttons[nextIndex].focus();
                }
                else if (upKey) {
                    e.preventDefault();
                    const prevIndex = currentIndex - 1;
                    if (prevIndex < 0) {
                        last === null || last === void 0 ? void 0 : last.focus();
                        return;
                    }
                    buttons[prevIndex].focus();
                }
                else if (buttons.length === 1 || ((!(itemList === null || itemList === void 0 ? void 0 : itemList.contains(currentItem)) || currentItem === last) && !shiftKey)) {
                    e.preventDefault();
                    first === null || first === void 0 ? void 0 : first.focus();
                }
                else if ((!(itemList === null || itemList === void 0 ? void 0 : itemList.contains(currentItem)) || currentItem === first) && shiftKey) {
                    e.preventDefault();
                    last === null || last === void 0 ? void 0 : last.focus();
                }
            }
            /**
             * @param e Click event
             */
            toggle(e) {
                var _a, _b;
                e.preventDefault();
                (_a = this.el) === null || _a === void 0 ? void 0 : _a.classList.remove("drop--collapsing", "drop--expanding");
                const shouldExpand = ((_b = this.menuButton) === null || _b === void 0 ? void 0 : _b.ariaExpanded) === "true";
                if (this.isCollapsing || !shouldExpand) {
                    this.expand();
                }
                else if (this.isExpanding || shouldExpand) {
                    this.collapse(e);
                }
            }
            expand() {
                var _a, _b;
                if (!this.el || !this.itemList)
                    return;
                this.itemList.style.height = `${this.itemList.offsetHeight}px`;
                (_a = this.menuButton) === null || _a === void 0 ? void 0 : _a.setAttribute("aria-expanded", "true");
                this.el.classList.add("drop--expanding");
                this.isExpanding = true;
                this.animations.forEach(anim => anim.cancel());
                this.animations = [];
                const buttonEls = this.itemList.querySelectorAll("button");
                const buttons = Array.from(buttonEls || []);
                const startHeight = this.itemList.offsetHeight || 0;
                const endHeight = ((_b = this.itemList.firstElementChild) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 0;
                const itemListAnim = this.itemList.animate({ height: [`${startHeight}px`, `${endHeight}px`] }, {
                    duration: this.transDuration,
                    easing: "cubic-bezier(0.33,1,0.68,1.33)"
                });
                itemListAnim.onfinish = this.animActionsExpand.onfinish;
                itemListAnim.oncancel = this.animActionsExpand.oncancel;
                this.animations.push(itemListAnim);
                buttons.forEach((button, i) => {
                    const buttomAnim = button.animate({ transform: ["translateY(100%)", "translateY(0)"] }, {
                        duration: this.transDuration,
                        delay: this.transDuration / 12 * i,
                        easing: "cubic-bezier(0.33,1,0.68,1)"
                    });
                    this.animations.push(buttomAnim);
                });
                this.el.style.setProperty("--drop-flare-dist", `${endHeight}px`);
            }
            /**
             * @param e Click event
             */
            collapse(e) {
                var _a, _b, _c;
                if (!this.el || !this.itemList)
                    return;
                this.el.classList.add("drop--collapsing");
                this.isCollapsing = true;
                this.animations.forEach(anim => anim.cancel());
                this.animations = [];
                const clickedButton = e.target;
                const buttonEls = (_a = this.itemList) === null || _a === void 0 ? void 0 : _a.querySelectorAll("button");
                const buttons = Array.from(buttonEls || []);
                const startHeight = ((_b = this.itemList) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 0;
                const endHeight = 0;
                const easing = "cubic-bezier(0.33,1,0.68,1)";
                const itemListAnim = this.itemList.animate({ height: [`${startHeight}px`, `${endHeight}px`] }, { duration: this.transDuration, easing });
                itemListAnim.onfinish = this.animActionsCollapse.onfinish;
                itemListAnim.oncancel = this.animActionsCollapse.oncancel;
                this.animations.push(itemListAnim);
                buttons.forEach((button, i) => {
                    if (clickedButton.value) {
                        button.classList.remove("drop__btn--selected");
                    }
                    const delayInc = this.transDuration / 12;
                    const buttomAnim = button.animate({ transform: ["translateY(0)", "translateY(100%)"] }, {
                        duration: this.transDuration,
                        delay: delayInc * (buttons.length - 1) - (delayInc * i),
                        easing
                    });
                    this.animations.push(buttomAnim);
                });
                if (clickedButton.value) {
                    clickedButton.classList.add("drop__btn--selected");
                    if (this.menuButton) {
                        const optionFound = this.options.find(option => option.name === clickedButton.value);
                        this.menuButton.textContent = (optionFound === null || optionFound === void 0 ? void 0 : optionFound.friendlyName) || "";
                    }
                }
                (_c = this.menuButton) === null || _c === void 0 ? void 0 : _c.focus();
                this.el.style.setProperty("--drop-flare-dist", `${endHeight}px`);
            }
            /**
             * @param open Menu should be expanded
             */
            onAnimationFinish(open) {
                var _a, _b;
                if (!this.el || !this.itemList)
                    return;
                (_a = this.menuButton) === null || _a === void 0 ? void 0 : _a.setAttribute("aria-expanded", `${open}`);
                this.animations = [];
                this.isCollapsing = false;
                this.isExpanding = false;
                this.itemList.style.height = "";
                (_b = this.el) === null || _b === void 0 ? void 0 : _b.classList.remove("drop--collapsing", "drop--expanding");
            }
        }

    </script>
</body>

</html>

Conclusion:

Creating an Animated Dropdown Menu using HTML, CSS, and JavaScript has been an exciting and educational journey. By combining HTML for structure, CSS for styling and animations, and JavaScript for interactivity, we’ve learned how to create an engaging user interface element that enhances the overall user experience of a website.

If Your Project is Not Working or Has Any Problem Don’t Worry, Just Click on Below Download Assets File And You Will Be Able To Get Full Control Of Our Projects , Then Customize And Use it For Your Coding Journey. Let the coding adventure begin!

By Downloading this assets You Will Be Able to create an Animated Dropdown Menu using HTML, CSS, and JavaScript , Which Can Be Used For Several Projects i.e. A Flutter App Using Vs Code or For Android App Using Android Studio And Also For Custom Web Development.

Leave a Reply

Your email address will not be published. Required fields are marked *