flowbite-react icon indicating copy to clipboard operation
flowbite-react copied to clipboard

<Accordion.Panel isOpen={true}> doesn't work also setOpen and isOpen doesn't work with props

Open iliafaramarzpour opened this issue 2 years ago • 23 comments

Describe the bug In the project, I need to manage the accordions panel and be able to open and close them, but I can't, I also checked the Flowbite codes and realized that they are not written correctly.

Expected behavior I want to manage isOpen and setOpen from the accordion panel and they work correctly.

Screenshots Screenshot 2023-05-10 at 3 01 34 PM

System information:

  • Device: Mac
  • Browser: Chrome

Project information:

  • Tailwind: ^3.2.4
  • Flowbite: ^1.6.0
  • Flowbite React: ^0.4.2
  • Type: Next.js - 13.4.1

iliafaramarzpour avatar May 10 '23 11:05 iliafaramarzpour

Sorry, I don't get the problem. Can you give more details? All the examples inside the documentation page seem to work properly.

You can get the source code to the examples here: https://github.com/themesberg/flowbite-react/blob/main/src/docs/pages/AccordionPage.tsx

PS: If you cold add a video demonstrating the problem, it would be better to understand, or to provide a sample project.

rluders avatar May 10 '23 11:05 rluders

Sorry, I don't get the problem. Can you give more details? All the examples inside the documentation page seem to work properly.

You can get the source code to the examples here: https://github.com/themesberg/flowbite-react/blob/main/src/docs/pages/AccordionPage.tsx

PS: If you cold add a video demonstrating the problem, it would be better to understand, or to provide a sample project.

I have a form for the user's profile in each accordion panel, and I want the user to see a SAVE button at the end of each accordion panel and open the next accordion panel after clicking the button. It means that I can control which accordion panel is open with a state and manage its opening and closing.

iliafaramarzpour avatar May 10 '23 12:05 iliafaramarzpour

Sorry, I don't get the problem. Can you give more details? All the examples inside the documentation page seem to work properly.

You can get the source code to the examples here: https://github.com/themesberg/flowbite-react/blob/main/src/docs/pages/AccordionPage.tsx

PS: If you cold add a video demonstrating the problem, it would be better to understand, or to provide a sample project.

please read this : https://github.com/themesberg/flowbite-react/tree/main/src/lib/components/Accordion 
And see how the logic of isOpen and setOpen is written in Accordion.tsx and AccordionPanel.tsx files.

iliafaramarzpour avatar May 10 '23 12:05 iliafaramarzpour

I still don't get it. Can you provide an example project?

rluders avatar May 13 '23 11:05 rluders

I'm also having this problem myself. In a very simple use case:

const [isOpen, setIsOpen] = useState(false);
  const toggleAccordion = () => {
    setIsOpen(!isOpen);
    console.log(isOpen)
  };
  return (
   <>
    <Accordion>
      <AccordionPanel isOpen={isOpen}>
        <AccordionTitle theme={accordionTitleTheme}>Hello</AccordionTitle>
        <AccordionContent>World</AccordionContent>
      </AccordionPanel>
    </Accordion>
          <Button onClick={toggleAccordion}>
          {isOpen ? 'Close Accordion' : 'Open Accordion'}
        </Button>
        </>);

Does not seem to open or close the accordion panel accordingly. The isOpen state is being changed, but the state is not being reflected by the accordionPanel.

realvandi avatar May 22 '23 16:05 realvandi

To note here is that I've also attempted using the setOpen prop for AccordionPanel, which imo is lacking documentation on how it's supposed to be used. As someone trying to use AccordionPanel, the setOpen prop is lacking description on how it's supposed to be used, and what it's for.

realvandi avatar May 22 '23 17:05 realvandi

@realvandi documentation update should be coming soon. The library wasn't released yet, so, it is expected to have missing documentation, but the code is always your best friend in this case.

rluders avatar May 22 '23 17:05 rluders

@rluders thanks for the quick response, it's very much appreciated. In the meanwhile, any hints on what could be done in order to trigger the opening/closing of the AccordionPanel? I can't seem to figure out what's wrong, even after reading through the code. Any answer would be much appreciated, thanks again for responding

realvandi avatar May 22 '23 18:05 realvandi

@IuriPires can you help on this one? I'm not sure when I'll have time to test it right now.

rluders avatar May 22 '23 20:05 rluders

@IuriPires can you help on this one? I'm not sure when I'll have time to test it right now.

Sure!!

IuriPires avatar May 23 '23 09:05 IuriPires

Could someone confirm if the issue still exists?

rluders avatar Jul 25 '23 18:07 rluders

Stumbled upon this thread since I ran into the same problem. I believe this is still an issue. My use case calls for the accordion panels to default open.

    <Accordion alwaysOpen>
      <Accordion.Panel isOpen={true}>
        <Accordion.Title>
          One
        </Accordion.Title>
        <Accordion.Content>
          1
        </Accordion.Content>
      </Accordion.Panel>
      <Accordion.Panel isOpen={true}>
        <Accordion.Title>
          Two
        </Accordion.Title>
        <Accordion.Content>
          2
        </Accordion.Content>
      </Accordion.Panel>
    </Accordion>

Here, only the "One" accordion panel is open when both should be open. I am using the latest npm version [email protected]

mwesterham avatar Jul 26 '23 19:07 mwesterham

I believe the setOpen callback may also not fire as well. (I assume this is meant to fire when the panel opens?)

mikeknapp avatar Aug 02 '23 04:08 mikeknapp

Is this working? I'm trying the isOpen prop and it's not responding. Please help

<Accordion>
      <Accordion.Panel itemID="panel1" >
        <Accordion.Title>Panel 1</Accordion.Title>
        <Accordion.Content>          
          panel 1 content
        </Accordion.Content>
      </Accordion.Panel>
      <Accordion.Panel itemID="panel2" isOpen={true}>
        <Accordion.Title>Panel 2</Accordion.Title>
        <Accordion.Content>          
          panel 2 content
        </Accordion.Content>
      </Accordion.Panel>
</Accordion>

mcwachanga avatar Sep 27 '23 13:09 mcwachanga

anyone managed to make it work?

dima-kov avatar Dec 22 '23 16:12 dima-kov

I'm also having the issue. any one got a fix?

bonesoul avatar Apr 05 '24 05:04 bonesoul

Same issue here

MrMavin avatar May 23 '24 12:05 MrMavin

same issue here, trying to use isOpen to make all panels open by default but it is not working

s0ngyang avatar Jun 04 '24 08:06 s0ngyang

In my Case I was tried to use accordion with map iterator but it does not work properly.

I hope this usage can help someone.

const [isClosed, setIsClosed] = useState<boolean[]>(matchedHistory.map(() => true)); 

const handleOpen = (index: number) => {
    const newIsClosed = [...isClosed];
    newIsClosed[index] = !isClosed[index];
    setIsClosed(newIsClosed);
  };

  const handleOnPanel = (index: number) => {
    setIsClosed(items.map(() => true));
  };


<Accordion collapseAll arrowIcon={() => null}> // Remove existing default arrowIcon
      { items.map((item,index) => (
            <Accordion.Panel key={index}>
             <Accordion.Title
            onClick={() => handleOpen(index)}
          >
              <span>{Items.title}</span> 
              <AccordionArrow isOpen={!isClosed[index]} /> // AccordionArrowIcon goes here
          </Accordion.Title>
          <Accordion.Content hidden={isClosed[index]}> //  Decide the content to hide or shown
            <p>
              <b>item.content</b> 
            </p>
          <Button onClick={() => handleOnPanel(index)}>SomeButton</Button>
          </Accordion.Content>
        </Accordion.Panel>
      ))}
</Accordion>
    

And this is arrow icon component above. Just incase you want to use library here is url clsx twMerge


const AccordionArrow = ({ isOpen }: { isOpen: boolean }) => (
    <svg
      stroke="currentColor"
      fill="currentColor"
      strokeWidth="0"
      viewBox="0 0 20 20"
      aria-hidden="true"
      className={twMerge(
        "h-6 w-6 shrink-0",
        clsx(isOpen ? "rotate-180" : "rotate-0"),
      )}
      data-testid="flowbite-accordion-arrow"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fillRule="evenodd"
        d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
        clipRule="evenodd"
      ></path>
    </svg>
  );

ChoiSeongmuk avatar Jul 31 '24 03:07 ChoiSeongmuk

This is still an issue, have not found a workaround

samjimenez-max avatar Feb 26 '25 16:02 samjimenez-max

I'm running into this as well, version 0.11.1 here. Do we know if #1404 fixes the issue, assuming it hasn't bitrotted? Odd that it hasn't even been commented on.

kelnos avatar Apr 02 '25 05:04 kelnos

Unfortunately we'll have to rewrite the component from scratch, entirely, the current state its... yeah, not much to say.

SutuSebastian avatar Apr 02 '25 07:04 SutuSebastian

I am using flowbite-react version 0.10.2 Having a workaround. Since the main context logic is inside AccordionPanel, and can be fully replaced by passing alwaysOpen={false}. So I made my own <HomemadeAccordion /> to replace original <Accordion /> like the following, then I can fully controlled which tab to open.

const HomemadeAccordion = (props: AccordionProps) => {
  const [isOpen, setOpen] = useState(props.collapseAll ? -1 : 0);

  const panels = useMemo(
    () =>
      Children.map(props.children, (child, i) =>
        cloneElement(child, {
          alwaysOpen: props.alwaysOpen,
          arrowIcon: child.props.arrowIcon ?? props.arrowIcon ?? ChevronDown,
          flush: props.flush,
          isOpen: child.props.isOpen ?? isOpen === i,
          setOpen:
            child.props.setOpen ?? (() => setOpen(isOpen === i ? -1 : i)),
        }),
      ),
    [props.alwaysOpen, props.arrowIcon, props.children, props.flush, isOpen],
  );

  const theme = merge(fbTheme.accordion.root, props.theme);

  return (
    <div
      className={cn(
        theme.base,
        theme.flush[props.flush ? "on" : "off"],
        props.className,
      )}
      data-testid="flowbite-accordion"
      {...props}
    >
      {panels}
    </div>
  );
};

in this case, i can fully controlled the <Accordion.Panel /> open state

const [accordionOpen, setAccordionOpen] = useState<string[] | null>(null);

<HomemadeAccordion>
  {[
    {
      title: t("Test Section"),
      id: "test",
      content: "Test Content 1",
    },
    {
      title: t("Test Section 2"),
      id: "test2",
      content: "Test Content 2",
    },
  ].map((section) => (
    <Accordion.Panel
      key={section.id}
      alwaysOpen={false}
      flush={false}
      isOpen={accordionOpen?.includes(section.id) || false}
      setOpen={() => setAccordionOpen((prev) => xor(prev, [section.id]))}
    >
      <Accordion.Title>{section.title}</Accordion.Title>
      <Accordion.Content>{section.content}</Accordion.Content>
    </Accordion.Panel>
  ))}

</HomemadeAccordion>

pkyPeter avatar Jul 24 '25 06:07 pkyPeter