---
title: Accordion
description: A vertically stacked set of interactive headings that each reveal an associated section of content built with Headless UI.
author:
  name: imskyleen
  url: https://github.com/imskyleen
---

<ComponentPreview name="headless-accordion-demo" />

## Installation

<ComponentInstallation name="headless-accordion" />

## Usage

```tsx
<Accordion>
  <AccordionItem>
    <AccordionButton>Accordion Item 1</AccordionButton>
    <AccordionPanel>Accordion Content 1</AccordionPanel>
  </AccordionItem>
  <AccordionItem>
    <AccordionButton>Accordion Item 2</AccordionButton>
    <AccordionPanel>Accordion Content 2</AccordionPanel>
  </AccordionItem>
  <AccordionItem>
    <AccordionButton>Accordion Item 3</AccordionButton>
    <AccordionPanel>Accordion Content 3</AccordionPanel>
  </AccordionItem>
</Accordion>
```

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://headlessui.com/react/disclosure" text="Docs" />
  <ExternalLink
    href="https://headlessui.com/react/disclosure#component-api"
    text="API Reference"
  />
</div>

### Animate UI props

#### AccordionButton

<TypeTable
  type={{
    transition: {
      description: 'The transition of the accordion button',
      type: 'Transition',
      required: false,
      default: "{ type: 'spring', stiffness: 150, damping: 17 }",
    },
    chevron: {
      description: 'Whether to show the accordion chevron',
      type: 'boolean',
      required: false,
      default: 'true',
    },
  }}
/>

#### AccordionPanel

<TypeTable
  type={{
    transition: {
      description: 'The transition of the accordion panel',
      type: 'Transition',
      required: false,
      default: "{ type: 'spring', stiffness: 150, damping: 17 }",
    },
  }}
/>

## Don't delete from the DOM

The choice made is the same as Headless UI, i.e. to remove the element from the DOM for accessibility and performance reasons. However, this may pose a problem for SEO. If you want your Accordion content to be taken into account by Google, please **replace the DisclosurePanel component with (because the Accordion component is based on the Disclosure component)**:

```tsx title="components/animate-ui/headless/disclosure.tsx"
function DisclosurePanel<TTag extends React.ElementType = typeof motion.div>(
  props: DisclosurePanelProps<TTag>,
) {
  const {
    className,
    children,
    transition = { type: 'spring', stiffness: 150, damping: 22 },
    as = motion.div,
    unmount,
    ...rest
  } = props;
  const { isOpen } = useDisclosure();

  return (
    <DisclosurePanelPrimitive
      static
      as={as as React.ElementType}
      unmount={unmount}
    >
      {(bag) => (
        <motion.div
          initial={false}
          animate={
            isOpen
              ? { height: 'auto', opacity: 1, '--mask-stop': '100%' }
              : { height: 0, opacity: 0, '--mask-stop': '0%' }
          }
          transition={transition}
          style={{
            maskImage:
              'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',
            WebkitMaskImage:
              'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',
          }}
          className={cn('overflow-hidden', className)}
          ref={ref}
          {...rest}
        >
          {typeof children === 'function' ? children(bag) : children}
        </motion.div>
      )}
    </DisclosurePanelPrimitive>
  );
}
```

## Credits

- We use [Headless UI](https://headlessui.com/react/disclosure) for the disclosure component.
- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/accordion) for the accordion style.
