Search code examples
javascripthtmlcssreactjsresponsive-design

Button Dropdown Feature


I have the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dropdown Menu</title>
    <style>
        .custom-box {
            background-color: #ff5733;
            padding: 20px;
            border-radius: 10px;
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            font-family: Arial, sans-serif;
        }

        .box-title {
            font-size: 24px;
            font-weight: bold;
            color: #fff;
        }

        .box-content {
            margin-top: 10px;
            font-size: 18px;
            color: #333;
        }

        .custom-button {
            background-color: #ff8f33;
            color: #fff;
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin-top: 20px;
        }

        .custom-button:hover {
            background-color: #ff5722;
        }

        .dropdown-content {
            display: none;
            flex-direction: column;
            align-items: center;
        }

        .dropdown-item {
            margin: 10px 0;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="custom-box">
        <div class="box-title">Dropdown Menu</div>
        <div class="box-content">
            Sample Text
        </div>
        <button class="custom-button" id="dropdown-button">Click Me</button>
        <div class="dropdown-content" id="dropdown-menu">
            <div class="dropdown-item">Dropdown Text</div>
            <div class="dropdown-item">Sample Text</div>
            <div class="dropdown-item">Sample Text</div>
        </div>
    </div>

    <script>
        const dropdownButton = document.getElementById('dropdown-button');
        const dropdownMenu = document.getElementById('dropdown-menu');

        dropdownButton.addEventListener('click', () => {
            dropdownMenu.style.display = dropdownMenu.style.display === 'none' ? 'flex' : 'none';
        });
    </script>
</body>
</html>

In this code, the "Not Dropdown Text" represents any text which doesn't have dropdown capabilities; however, "Dropdown Text" refers to a text that can be further expanded to show hidden text.

How can I achieve the dropdown within this dropdown box? When I click the text that has further dropdown capabilities, it should display hidden text inside the box.


Solution

  • One solution is to have a list within your list that has more data.

    I also changed the click handler for the panel itself to the title. This way you can click the elements within the body to open/close.

    document.querySelector('.tile-label')
      .addEventListener('click', function() {
        const _parent = this.parentNode;
        _parent.classList.toggle('expanded');
        const plus = _parent.querySelector('.plus');
        plus.style.transform = _parent.classList.contains('expanded') ? 'rotate(45deg)' : 'rotate(0)';
      });
    
    const toggleChild = (e) => {
    
      if (e.currentTarget == e.target) {
        const el = e.target;
        el.classList.toggle("active")
      }
    }
    
    const level2 = document.querySelectorAll(".hidden-text ul li:has(ul)");
    
    level2.forEach((li) => li.addEventListener("click", toggleChild))
    .tile-container {
      padding: 5px;
      font-size: 25px;
    }
    
    .rectangle {
      background-color: #0051a5;
      padding-right: 1em;
      padding-top: 1em;
      border-radius: 1em;
      display: grid;
      grid-template-rows: 1fr auto;
      grid-template-columns: auto 1em;
      grid-template-areas: "sample plus" "extratext extratext";
    }
    
    .plus {
      grid-area: plus;
      background: linear-gradient(#0051a5 0 0), linear-gradient(#0051a5 0 0), #fff;
      background-position: center;
      background-size: 60% 2.5px, 2.5px 60%;
      background-repeat: no-repeat;
      transition: transform 0.3s ease;
    }
    
    .radius {
      border-radius: 50%;
      width: 1em;
      height: 1em;
      margin-right: 1em;
    }
    
    .tile-label {
      grid-area: sample;
      font-family: 'PT Sans Narrow', sans-serif;
      font-size: 1em;
      text-transform: uppercase;
      cursor: pointer;
      font-weight: 600;
      color: #fff;
      padding-left: 1em;
      height: 2em;
    }
    
    .tile-accent {
      color: #FFC72C;
    }
    
    .hidden-text {
      grid-area: extratext;
      display: none;
      font-family: 'PT Sans Narrow', sans-serif;
      font-size: 0.75em;
      background-color: #fff;
      color: #000;
      margin: 1em;
      padding-top: 0.5em;
      padding-left: 1em;
    }
    
    .expanded>.hidden-text {
      display: block;
      animation: fade-in 1s;
    }
    
    @keyframes fade-in {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    
    @keyframes fade-out {
      from {
        opacity: 1;
      }
      to {
        opacity: 0;
      }
    }
    
    
    /*Hides the child list be default*/
    
    .hidden-text ul li ul {
      display: none;
    }
    
    
    /*active class toggles the visibility of the sub elements*/
    
    .hidden-text ul li.active ul{
      display: block;
    }
    
    li .plus{
      transform:rotate(0);
    }
    
    li.active .plus{
      transform:rotate(45deg);
    }
    
    /*changes the cursor to a pointer for the list items that have a child ul*/
    
    .hidden-text ul li:has(ul) .plus {
      float:right
    }
    
    .hidden-text ul li:has(ul) {
      cursor: pointer;
    }
    <head>
      <link rel="preconnect" href="https://fonts.googleapis.com">
      <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
      <link href="https://fonts.googleapis.com/css2?family=PT+Sans+Narrow:wght@400;700&display=swap" rel="stylesheet">
    </head>
    
    <body>
      <div class="tile-container">
        <div class="rectangle">
          <div class="plus radius"></div>
          <div class="tile-label">
            Sample <span class="tile-accent">Text</span>
          </div>
          <div class="hidden-text">
            <ul>
              <li>Not Dropdown Text</li>
              <li>Dropdown Text <div class="plus radius"></div>
                <ul>
                  <li>More Text!!</li>
                </ul>
              </li>
              <li>Not Dropdown Text</li>
            </ul>
          </div>
        </div>
      </div>
    </body>