Search code examples
cssvue.jstailwind-cssdaisyui

DaisyUI Nested collapse elements with dropdown menu


This is a follow up from this question. Now, I am using the solution from this question in my Vue component, updated the collapse part and now it's a nested collapse with some collapse elements inside.

The issue now is that if I put !overflow-visible on the main collapse, overriding it, the elements inside of it are not hidden anymore and they're overflowing from the collapse despite it being closed.

How can I solve this behaviour? I tried adding overflow-hidden to the children of the collapse but because of inheritance, the overflow-hidden doesn't do anything. Also one thing I noticed is that even though the collapse with the dropdown has a z-index of 99, it's not showing above everything else which it should do.

<template>
  <div
    v-for="index in 3"
    tabindex="0"
    class="collapse !overflow-visible collapse-plus z-0 rounded-lg border border-base-content bg-base-100 shadow-md md:w-[48.75%]"
    :class="collapse ? 'collapse-open' : 'collapse-close'"
  >
    <div
      class="collapse-title !overflow-hidden flex items-center text-lg font-medium"
      :class="collapse ? 'bg-primary' : 'bg-base-100'"
      @click="OnClick"
    >
      <div
        class="mr-3 grid h-[58px] !overflow-hidden w-[62px] place-content-center rounded-lg"
        :class="collapse ? 'bg-base-100' : 'bg-primary'"
      ></div>
      <div
        class="flex flex-col gap-1"
        :class="collapse ? 'text-base-100' : 'text-primary'"
      >
        Test
        <div class="badge badge-success rounded-[4px]">Active</div>
      </div>
    </div>
    <div class="collapse-content bg-base-200 !p-0 text-accent">
      <div
        tabindex="0"
        class="collapse collapse-open border border-base-300 bg-red-200 !overflow-visible"
      >
        <div class="collapse-title text-xl font-medium">
          I have collapse-open class
        </div>
        <div class="collapse-content !overflow-visible">
          <h2>HELLLERGLERL</h2>
          <h2>HELLLERGLERL</h2>
          <h2>HELLLERGLERL</h2>
          <h2>HELLLERGLERL</h2>
          <h2>HELLLERGLERL</h2>
          <h2>HELLLERGLERL</h2>
          <details class="dropdown dropdown-end z-[99]">
            <summary class="m-1 btn">open or close</summary>
            <ul
              class="p-2 shadow menu dropdown-content z-[98] bg-base-100 rounded-box w-52"
            >
              <li><a>Item 1</a></li>
              <li><a>Item 2</a></li>
              <li><a>Item 1</a></li>
              <li><a>Item 2</a></li>
              <li><a>Item 1</a></li>

              <li><a>Item 2</a></li>
            </ul>

            <div
              tabindex="0"
              class="collapse collapse-open border border-base-300 bg-blue-200 !overflow-visible"
            >
              <div class="collapse-title text-xl font-medium">
                I have collapse-open class
              </div>
              <div class="collapse-content">
                <details class="dropdown">
                  <summary class="m-1 btn">open or close</summary>
                  <ul
                    class="p-2 shadow menu dropdown-content z-[99] bg-base-100 rounded-box w-52"
                  >
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                    <li><a>Item 1</a></li>
                    <li><a>Item 2</a></li>
                  </ul>
                </details>
              </div>
            </div>
          </details>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const collapse = ref(false);

function OnClick() {
  collapse.value = !collapse.value;
}
</script>


Solution

  • You could consider using the <Teleport> built-in to render the drop-down menu outside the collapsible elements. This then negates the need to juggle overflow: visible/hidden. You would need to manually position the dropdowns yourself however, since they will no longer be inside the same parent as the dropdown buttons.

    Here is a naïve example that demonstrates the concept:

    const { createApp, ref } = Vue;
    
    const dropdown = {
      setup() {
        const open = ref(false);
        const button = ref();
        const style = ref({});
        
        const toggle = () => {
          open.value = !open.value;
          if (open.value) {
            const rect = button.value.getBoundingClientRect();
            
            style.value.top = `${rect.top + window.scrollY}px`;
            style.value.left = `${rect.left + window.scrollX + rect.width}px`;
          }
        };
        
        return { open, toggle, button, style };
      },
      template: '#dropdown',
    };
    
    createApp({
      components: {
        dropdown,
      },
      setup() {
        const collapse = ref(false);
    
        function OnClick() {
          collapse.value = !collapse.value;
        }
        
        return { collapse, OnClick };
      }
    }).mount('#app')
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.13/vue.global.prod.min.js" integrity="sha512-dJsT2VK9KxehzZYzxzUELznI6velu2pAOwpkL5jj4TQQhTNGXZUMup7aLqgqNwVPSUF/Ntcdfla3BEcfC7zwCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.min.css" rel="stylesheet" type="text/css" />
    <script src="https://cdn.tailwindcss.com/3.4.0"></script>
    
    <div id="app">
      <div
        v-for="index in 3"
        tabindex="0"
        class="collapse collapse-plus z-0 rounded-lg border border-base-content bg-base-100 shadow-md md:w-[48.75%]"
        :class="collapse ? 'collapse-open' : 'collapse-close'"
      >
        <div
          class="collapse-title flex items-center text-lg font-medium"
          :class="collapse ? 'bg-primary' : 'bg-base-100'"
          @click="OnClick"
        >
          <div
            class="mr-3 grid h-[58px] w-[62px] place-content-center rounded-lg"
            :class="collapse ? 'bg-base-100' : 'bg-primary'"
          ></div>
          <div
            class="flex flex-col gap-1"
            :class="collapse ? 'text-base-100' : 'text-primary'"
          >
            Test
            <div class="badge badge-success rounded-[4px]">Active</div>
          </div>
        </div>
        <div class="collapse-content bg-base-200 !p-0 text-accent">
          <div
            tabindex="0"
            class="collapse collapse-open border border-base-300 bg-red-200"
          >
            <div class="collapse-title text-xl font-medium">
              I have collapse-open class
            </div>
            <div class="collapse-content">
              <h2>HELLLERGLERL</h2>
              <h2>HELLLERGLERL</h2>
              <h2>HELLLERGLERL</h2>
              <h2>HELLLERGLERL</h2>
              <h2>HELLLERGLERL</h2>
              <h2>HELLLERGLERL</h2>
              <dropdown>
                <ul
                  class="p-2 shadow menu dropdown-content z-[98] bg-base-100 rounded-box w-52"
                >
                  <li><a>Item 1</a></li>
                  <li><a>Item 2</a></li>
                  <li><a>Item 1</a></li>
                  <li><a>Item 2</a></li>
                  <li><a>Item 1</a></li>
    
                  <li><a>Item 2</a></li>
                </ul>
                <template v-slot:content>
                  <div
                    tabindex="0"
                    class="collapse collapse-open border border-base-300 bg-blue-200"
                  >
                    <div class="collapse-title text-xl font-medium">
                      I have collapse-open class
                    </div>
                    <div class="collapse-content">
                      <dropdown>
                        <ul
                          class="p-2 shadow menu dropdown-content z-[99] bg-base-100 rounded-box w-52"
                        >
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                          <li><a>Item 1</a></li>
                          <li><a>Item 2</a></li>
                        </ul>
                      </dropdown>
                    </div>
                  </div>
                </template>
              </dropdown>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <template id="dropdown">
      <details class="dropdown dropdown-end z-[99]">
        <summary class="m-1 btn" @click="toggle" ref="button">open or close</summary>
        <Teleport to="body" v-if="open">
          <div class="absolute" :style="style">
            <slot></slot>
          </div>
        </Teleport>
    
        <slot name="content"></slot>
        </div>
      </details>
    </template>