React-Bootstrap Accordion Toggle, Multiple Open, & More: A Tutorial

The React Bootstrap Accordion is a great component with several useful props for controlling which items are open. We can even control whether multiple items are open at once and if a default is open on render.

We can also programmatically open an accordion item or collapse all accordion items, for example through a button click.

Here is what we will build:

React-Bootstrap Accordion with Multiple Items Open
React-Bootstrap Accordion with Multiple Items Open

Full code for this tutorial is in the Resources section.

React Bootstrap Accordion Multiple Open

The React Bootstrap Accordion can have multiple items open at once with a simple prop set to true:

<Accordion alwaysOpen>
  //...Items
</Accordion>

The alwaysOpen prop simply requires an item to be clicked to manually close it, instead of having an open item close when a different closed item is clicked for open.

Setting this prop is easy, but it adds complexity to the programmatic opening and closing of items as we’ll see below.

Here’s how to change the accordion open/close icon.

React Bootstrap Accordion Default Open

If we want to set a “default” open item, i.e. an item that is open on render, we need to use the defaultActiveKey prop. This prop takes either a string or an array of strings.

If alwaysOpen is false, then defaultActiveKey takes a string. If alwaysOpen is true, then we are dealing with the ability to open multiple items and we need arrays for controlling which items are open. In this case, the defaultActiveKey needs to be set to an array.

Keep in mind that the keys on the accordion are string values, for example “0” and “1”. Therefore, when we can have multiple open then the defaultActiveKey needs an array of strings if you want multiple open on default.

React Bootstrap Accordion Toggle Programmatically

We can programmatically toggle which accordion items are open by using a React useState hook and passing the state value into the activeKey prop on the accordion.

In this tutorial I added a toggle button that sets the useState value called activeKeys. The programmatic toggle code is different if we allow multiple items open or only one item open.

Here’s the code to programmatically toggle the accordion if we do not allow multiple items open at once. We have to choose what is toggled, and in this case I chose the toggle button to only open the first item:

const handleToggleClick = () => {
  if (activeKey === "0") {

    setActiveKey("");
  } else {
    setActiveKey("0");
  }
}

Notice that instead of calling the state value activeKeys plural I changed the name to activeKey because this won’t lead someone to think there can be multiple items open at once.

Here’s the code to toggle the first item if we do allow multiple items open at once. It is more complex because first we have to detect whether the first item is already in the array:

const handleToggleClick = () => {
  const index = activeKeys.indexOf("0");
  if (index > -1) {
    activeKeys.splice(index, 1);
    setActiveKeys([...activeKeys]);
  } else {
    setActiveKeys(activeKeys.concat("0"));
  }
}

If we have a programmatic toggle in place, then we need to pass the activeKeys value to the accordion with the activeKey prop. That means we also need an onSelect handler on the accordion so that when it changes value by click then the new value can flow to the activeKeys state value:

const handleSelect = (eventKey: AccordionEventKey) => setActiveKeys(eventKey as string[]);

//JSX
<Accordion alwaysOpen activeKey={activeKeys} onSelect={handleSelect}>

React Bootstrap Accordion Open and Collapse Programmatically

Some people refer to the open and close of the accordion items as toggling while others refer to it simply as “open and close”. We can programmatically open and close the accordion with the toggle code in the previous section.

However, we need to explore the TypeScript typing on the handleSelect. Notice the type eventKey: AccordionEventKey. AccordionEventKey is imported from 'react-bootstrap/AccordionContext' and is the actual proper typing of the eventKey value passed to the select handler.

I found that I needed to cast it to a string array and set my state value to a string array in order to be able to use array functions on my handleToggleClick function. There may have been a better way to handle this TypeScript issue, and please leave a comment if you find one.

React Bootstrap Accordion Toggle Not Working

If the accordion toggle is not working, then you likely have an issue in your onSelect handler. A likely cause of this is that you added programmatic open and close with a state value, but now your manual clicks of the accordion do not toggle it.

Check up on your onSelect and also make sure that the accordion’s activeKey prop is being properly passed a state value.

If you are not using programmatic toggling from an outside source, then your accordion toggle should simply work straight from the box. I suggest starting with this basic accordion in the React Bootstrap docs and building it out to meet your needs. The toggle is working great on it.

React Bootstrap Accordion Collapse All

All accordion items can be collapsed on an event trigger, such as the click of a button. This must be done programmatically from outside the accordion.

In this tutorial I added a “Collapse” button outside the tutorial. When it is clicked, I set the activeKeys to an empty array:

const handleCollapseClick = () => {
  setActiveKeys([]);
}

If I were not allowing multiple items to be open at once, then I would change the handler to setActiveKeys(""); instead of an empty array. An empty string in activeKeys will flow through to the activeKey prop on the accordion and the empty string will not match any item eventKey values, so all items will be closed.

Here’s what the accordion looks like after the button is clicked:

React Bootstrap Accordion Collapse All
React Bootstrap Accordion Collapse All

If you want to create a styled accordion, check out this tutorial.

Resources

Here is the full code for this accordion example:

//CustomToggleAccordion.scss
@import "bootstrap/scss/bootstrap";

//CustomTottleAccordion.tsx
import React from "react";
import Accordion from 'react-bootstrap/Accordion';
import Button from "react-bootstrap/Button";
import { AccordionEventKey } from 'react-bootstrap/AccordionContext';
import "./CustomToggleAccordion.scss";


export default function CustomToggleAccordion() {
  const [activeKeys, setActiveKeys] = React.useState(["0"]);
  const handleSelect = (eventKey: AccordionEventKey) => setActiveKeys(eventKey as string[]);
  const handleToggleClick = () => {
    const index = activeKeys.indexOf("0");
    if (index > -1) {
      activeKeys.splice(index, 1);
      setActiveKeys([...activeKeys]);
    } else {
      setActiveKeys(activeKeys.concat("0"));
    }
  }
  const handleCollapseClick = () => {
    setActiveKeys([]);
  }

  return (
    <div className="flex" style={{ minWidth: "40%" }}>
      <Accordion alwaysOpen activeKey={activeKeys} onSelect={handleSelect}>
        <Accordion.Item eventKey="0">
          <Accordion.Header>Accordion Item #1</Accordion.Header>
          <Accordion.Body>
            Body #1
          </Accordion.Body>
        </Accordion.Item>
        <Accordion.Item eventKey="1">
          <Accordion.Header>Accordion Item #2</Accordion.Header>
          <Accordion.Body>
            Body #2
          </Accordion.Body>
        </Accordion.Item>
        <Accordion.Item eventKey="2">
          <Accordion.Header>Accordion Item #3</Accordion.Header>
          <Accordion.Body>
            Body #3
          </Accordion.Body>
        </Accordion.Item>
        <Accordion.Item eventKey="3">
          <Accordion.Header>Accordion Item #4</Accordion.Header>
          <Accordion.Body>
            Body #4
          </Accordion.Body>
        </Accordion.Item>
      </Accordion>
      <div className="mt-5 d-flex justify-content-between">
        <Button onClick={handleToggleClick} >Toggle First</Button>
        <Button onClick={handleCollapseClick}>Collapse All</Button>
      </div>
    </div >
  );
}
Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.