Beta
Animate UI

Accordion

A vertically stacked set of interactive headings that each reveal an associated section of content built with Headless UI.

Made by imskyleen
Animate UI is an open-source distribution of React components built with TypeScript, Tailwind CSS, and Motion.

Installation

Usage

<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

Animate UI props

AccordionButton

PropTypeDefault
chevron?
boolean
true
transition?
Transition
{ type: 'spring', stiffness: 150, damping: 17 }

AccordionPanel

PropTypeDefault
transition?
Transition
{ 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):

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 for the disclosure component.
  • We take our inspiration from Shadcn UI for the accordion style.

Built by Skyleen. The source code is available on GitHub.

On this page