Skip to main content
/
/
/
Accordion

Accordion

import Accordion from "@intility/bifrost-react/Accordion";

Basic Accordion

The <Accordion> component provides a group of collapsible content, where only one panel is open at a time by default. Styling based on the .bf-accordion CSS class.

<Accordion> <Accordion.Item title="Thor about Loki"> There was one time when we were children, he transformed himself into a snake, and he knows that I love snakes. So, I went to pick up the snake to admire it, and he transformed back into himself and he was like, "Yeah, it's me!" And he stabbed me. We were eight at the time. </Accordion.Item> <Accordion.Item title="Initially open!" defaultActive> This item is opened initially with the <code>defaultActive</code> prop. </Accordion.Item> <Accordion.Item title={ <> Title can be <em>any</em> <code>JSX</code> content </> } > What happened to my manners? I haven't properly introduced myself. Come on. Follow me. My name is Grandmaster. I preside over a little harlequinade called the Contest of Champions. People come from far and wide to unwillingly participate in it. And you, my friend, might just be part of the new cast. What do you say to that? </Accordion.Item> <Accordion.Item title="Disabled item" disabled> This content cannot be toggled as long as the Accordion.Item is disabled. </Accordion.Item> </Accordion>
<Accordion> <Accordion.Item title="Thor about Loki"> There was one time when we were children, he transformed himself into a snake, and he knows that I love snakes. So, I went to pick up the snake to admire it, and he transformed back into himself and he was like, "Yeah, it's me!" And he stabbed me. We were eight at the time. </Accordion.Item> <Accordion.Item title="Initially open!" defaultActive> This item is opened initially with the <code>defaultActive</code> prop. </Accordion.Item> <Accordion.Item title={ <> Title can be <em>any</em> <code>JSX</code> content </> } > What happened to my manners? I haven't properly introduced myself. Come on. Follow me. My name is Grandmaster. I preside over a little harlequinade called the Contest of Champions. People come from far and wide to unwillingly participate in it. And you, my friend, might just be part of the new cast. What do you say to that? </Accordion.Item> <Accordion.Item title="Disabled item" disabled> This content cannot be toggled as long as the Accordion.Item is disabled. </Accordion.Item> </Accordion>
This item is opened initially because of the defaultActive prop.

Styled variant

<Accordion variant="styled"> <Accordion.Item title="Thor about Loki">[item content...]</Accordion.Item> [more items...] </Accordion>
<Accordion variant="styled"> <Accordion.Item title="Thor about Loki">[item content...]</Accordion.Item> [more items...] </Accordion>

With icon

<Accordion> <Accordion.Item icon={faQuoteRight} title="Thor about Loki"> [item content...] </Accordion.Item> [more items...] </Accordion>
<Accordion> <Accordion.Item icon={faQuoteRight} title="Thor about Loki"> [item content...] </Accordion.Item> [more items...] </Accordion>

Styled variant:

Compact (or responsive) mode

Both default and 'styled' variant supports mode='compact' which removes left/right border and the border radius, suitable for when the accordion itself should be full width inside a small container (like a modal, drawer or in a column layout).

The 'responsive' mode behaves like 'compact' but is only applied for mobile (smaller than 600px width) screens.

<Accordion mode='compact'>...</Accordion> <Accordion mode='compact' variant='styled'>...</Accordion>
<Accordion mode='compact'>...</Accordion> <Accordion mode='compact' variant='styled'>...</Accordion>

No padding

You can remove the padding inside content panels with <Accordion.Item noPadding>, useful when you have content that stretches the full width.

<Accordion> <Accordion.Item title="Default 100% width image"> <img src="/seal.jpg" style={{ width: "100%", display: "block" }} alt="Grumpy-looking seal" /> </Accordion.Item> <Accordion.Item noPadding title="noPadding and 100% width image"> <img src="/seal.jpg" style={{ width: "100%", display: "block" }} alt="Grumpy-looking seal" /> </Accordion.Item> </Accordion>
<Accordion> <Accordion.Item title="Default 100% width image"> <img src="/seal.jpg" style={{ width: "100%", display: "block" }} alt="Grumpy-looking seal" /> </Accordion.Item> <Accordion.Item noPadding title="noPadding and 100% width image"> <img src="/seal.jpg" style={{ width: "100%", display: "block" }} alt="Grumpy-looking seal" /> </Accordion.Item> </Accordion>

Secondary actions

By default, the entire title area of an <Accordion.Item> is clickable and will toggle its expanded state. If you need another action, you can pass <Accordion.Action> element(s) to the actions prop, which will be placed to the right of the clickable title area.

Clicks on the actions area will not toggle the expanded state of the accordion.

The aria-label allows us to supply a screen reader accessible label for any focusable items that don't have any text content.

<Accordion> <Accordion.Item title="Accordion.Action icon button" actions={ <Accordion.Action icon={faPencil} onClick={() => console.log("Edit ation clicked")} aria-label="Edit" /> } > ... </Accordion.Item> <Accordion.Item title="Link with icon and css classes" actions={ <a href="#path/to/edit" className="bf-accordion-action" aria-label="Edit"> <span className="bf-accordion-action-circle"> <Icon icon={faPencil} /> </span> </a> } > ... </Accordion.Item> </Accordion>
<Accordion> <Accordion.Item title="Accordion.Action icon button" actions={ <Accordion.Action icon={faPencil} onClick={() => console.log("Edit ation clicked")} aria-label="Edit" /> } > ... </Accordion.Item> <Accordion.Item title="Link with icon and css classes" actions={ <a href="#path/to/edit" className="bf-accordion-action" aria-label="Edit"> <span className="bf-accordion-action-circle"> <Icon icon={faPencil} /> </span> </a> } > ... </Accordion.Item> </Accordion>

Styled variant:

Multiple active items

Passing multiple to the <Accordion> allows multiple items to be open at the same time.

<Accordion multiple>...</Accordion>
<Accordion multiple>...</Accordion>

Radius

The radius prop allows customizing the border-radius size, useful when nesting multiple elements with rounded corners, or removing them when full-width inside a container. Valid values are:

  • "none" = no border radius
  • "xs" = 4px
  • "s" = 8px
  • "m" (or undefined) = 12px (default)
  • "l" = 16px
  • "xl" = 24px
<Accordion radius="s">...</Accordion>
<Accordion radius="s">...</Accordion>

Radius for styled variant

For default <Accordion>, it changes the outermost border-radius as shown above, but for variant="styled" it sets border-radius for each <Accordion.Item> child instead.

<Accordion radius="s" variant="styled"> <Accordion.Item>...</Accordion.Item> </Accordion>
<Accordion radius="s" variant="styled"> <Accordion.Item>...</Accordion.Item> </Accordion>

Sandbox

import Accordion from "@intility/bifrost-react/Accordion";

export default function AccordionDemo() {
  return (
    <Accordion>
      <Accordion.Item title="Thor about Loki">
        There was one time when we were children, he transformed himself into a
        snake, and he knows that I love snakes. So, I went to pick up the snake
        to admire it, and he transformed back into himself and he was like,
        "Yeah, it's me!" And he stabbed me. We were eight at the time.
      </Accordion.Item>
      <Accordion.Item title="Initially open!" defaultActive>
        This item is opened initially with the <code>defaultActive</code> prop.
      </Accordion.Item>
      <Accordion.Item
        title={
          <>
            Title can be <em>any</em> <code>JSX</code> content
          </>
        }
      >
        What happened to my manners? I haven't properly introduced myself. Come
        on. Follow me. My name is Grandmaster. I preside over a little
        harlequinade called the Contest of Champions. People come from far and
        wide to unwillingly participate in it. And you, my friend, might just be
        part of the new cast. What do you say to that?
      </Accordion.Item>
      <Accordion.Item title="Disabled item" disabled>
        This content cannot be toggled as long as the Accordion.Item is
        disabled.
      </Accordion.Item>
    </Accordion>
  );
}

Controlled mode

Accordion can be controlled with your own state by using the active and onClick props on each <Accordion.Item>.

import { useState } from "react";
import Accordion from "@intility/bifrost-react/Accordion";

export default function () {
  const [active, setActive] = useState(["strange", "thor"]);

  const handleChange = (key) => {
    if (!active.includes(key)) {
      setActive([...active, key]);
    } else {
      setActive(active.filter((pa) => pa !== key));
    }
  };
  return (
    <Accordion>
      <Accordion.Item
        title="Thor about Loki"
        active={active.includes("thor")}
        onClick={() => handleChange("thor")}
      >
        There was one time when we were children, he transformed himself into a
        snake, and he knows that I love snakes. So, I went to pick up the snake
        to admire it, and he transformed back into himself and he was like,
        "Yeah, it's me!" And he stabbed me. We were eight at the time.
      </Accordion.Item>
      <Accordion.Item
        title="Strange conversation"
        active={active.includes("strange")}
        onClick={() => handleChange("strange")}
      >
        <strong>Thor:</strong> If you knew where he was, why didn't you call me?
        <br />
        <strong>Dr. Strange:</strong> I have to tell you, he was adamant that he
        not be disturbed. Your father said he had chosen to remain in exile. And
        you don't have a phone.
        <br />
        <strong>Thor</strong>: No, I don't have a phone, but you could have sent
        an electronic letter. It's called an email.
        <br />
        <strong>Dr. Strange:</strong> Yeah, do you have a computer?
        <br />
        <strong>Thor:</strong> No. What for?
      </Accordion.Item>
      <Accordion.Item
        title="Grandmaster introduction"
        active={active.includes("grandmaster")}
        onClick={() => handleChange("grandmaster")}
      >
        What happened to my manners? I haven't properly introduced myself. Come
        on. Follow me. My name is Grandmaster. I preside over a little
        harlequinade called the Contest of Champions. People come from far and
        wide to unwillingly participate in it. And you, my friend, might just be
        part of the new cast. What do you say to that?
      </Accordion.Item>
    </Accordion>
  );
}