daisyui icon indicating copy to clipboard operation
daisyui copied to clipboard

Nested collapse elements & collapse menu

Open OguzcanKarakoc opened this issue 2 years ago • 4 comments

It is not possible to nest collapse elements.

<div tabindex="0" class="collapse">
  <div class="collapse-title text-xl font-medium">Focus me to see content</div>
  <div class="collapse-content">
    <div tabindex="1" class="collapse">
      <div class="collapse-title text-xl font-medium">Focus me to see content</div>
      <div class="collapse-content">
        <p>tabindex="0" attribute is necessary to make the div focusable</p>
      </div>
    </div>
  </div>
</div>

Also I am trying to create a collapsing (side) menu (for an admin dashboard). I have seen a discussing that is marked as resolved here. The "solution" does not seem to work:

<ul class="menu">
  <li><a href="#">Menu Item</a></li>
  <li><a href="#">Menu Item</a></li>
  <li tabindex="0" class="collapse">
    <span class="collapse-title">Sub Menu Title</span>
    <ul class="collapse-content">
      <li><a href="#">Sub menu</a></li>
      <li><a href="#">Sub menu</a></li>
      <li><a href="#">Sub menu</a></li>
    </ul>
  </li>
  <li><a href="#">Menu Item</a></li>
</ul>

Perhaps the menu can be created as a separate issue.

OguzcanKarakoc avatar Aug 13 '22 21:08 OguzcanKarakoc

I got it to work when you use the checkbox method for the Collapse Component.

Here is Tailwind Playground Example

Hope this helps.

rhscjohn-dev avatar Aug 16 '22 19:08 rhscjohn-dev

Running into this same issue ☹️

Not only will the nested collapse's collapse-open & collapse-closed classes not work, it also messes up the smooth transition on the parent's collapse.

nenorrell avatar Aug 28 '22 19:08 nenorrell

As @rhscjohn-dev it works with checkbox method.
It's not possible with the focus method, because on a HTML page we can only focus one element at a time. When a collapse is focused, its content will be visible, as soon as we focus on another element (including the child collapse) the focus is lost and the parent will get closed.

@nenorrell I will be improving the selectors so it will work with the class names as well.

Let me know if you have any questions.

saadeghi avatar Aug 29 '22 00:08 saadeghi

If anyone is looking for an interim workaround, I resolved this issue by doing the following:

(This example is a React component but the concept should apply outside of React as well)

import React, { PropsWithChildren, ReactNode, useState } from "react";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";

interface ICollapse {
    defaultExpand ?:boolean
    headerContent :string | ReactNode
    headerClasses ?:string[]
    leftIcon ?:IconDefinition
}
export const Collapse = (props :PropsWithChildren<ICollapse>) => {
    const [isExpanded, setIsExpanded] = useState<boolean>(props.defaultExpand || false);
    return (
        <div className="w-100">
            <div className={`collapse-title cursor-pointer flex items-center justify-center
                ${props.headerClasses?.join(" ") || ""}`
            }
            onClick={()=> setIsExpanded(!isExpanded) }>
                {
                    props.leftIcon ? <FontAwesomeIcon icon={props.leftIcon} className="mr-2" /> : null
                }
                <div className="w-full">{props.headerContent}</div>
                <p className={`items-end transition ease-in-out ${isExpanded ? "" : "-rotate-90"}`}>
                    <FontAwesomeIcon icon={faChevronDown}/>
                </p>
            </div>
            <div
                className={`ease-linear duration-[1000ms] transition-[height] overflow-hidden 
                    ${isExpanded ? "h-fit" : "h-0"}
                `}
            >
                {props.children}
            </div>
        </div>
    );

It can then be consumed (in React) as:

export const SomeComponent = () => {
    return (
        <div className="row-auto">
            <div className="mx-5 mt-5 bg-base-100 rounded-md text-base-content">

                <Collapse
                    defaultExpand={true}
                    headerContent="This is the parent collapse"
                    headerClasses={['text-xl', 'font-medium', 'bg-primary', 'text-primary-content']}
                    leftIcon={faLayerGroup}
                >

                    <Collapse
                        leftIcon={faSignsPost}
                        headerContent={
                            <div className="text-lg flex items-center">
                                <div className={`mx-2 p-1 px-2 w-20 text-center rounded-md inline-block`}>
                                This is the child collapse with extra HTML structure
                                </div>
                                <div className="rounded-md inline-block bg-base-300 text-base-content p-1 px-2 w-100">Some Title</div>
                            </div>
                        }
                        defaultExpand={defaultExpand}
                    >
                    </Collapse>

                </Collapse>

            </div>
        </div>
    );
};

This should give you the expected functionality

nenorrell avatar Sep 19 '22 21:09 nenorrell