Search code examples
javascriptreactjsstyled-components

How to make accordion menu using react & styled components


I'm trying to create an accordion menu like the one from Bootstrap https://getbootstrap.com/docs/4.3/components/collapse/

I have managed to get it to open and close fine, but I'm missing the smooth transition :/

It's like the transition is just not being applied.

import React, { useState } from 'react';
import styled from 'styled-components';
import { Button } from './common/button';

const AccordionWrapper = styled.div`
    display: flex;
    flex-direction: column;
    justify-content: center;
    background-color: var(--Secondary-color-dark);
    border-radius: 10px;
    height: auto;
    padding: 2%;
    text-align: center;
    transition: all 0.6s ease-in-out;
`;

const InternalWrapper = styled.div`
    width: 100%;
    max-height: ${(props) => (props.open ? '100%' : '0')};
    transition: all 1s ease-in-out;
    overflow: hidden;
`;

const Accordion = ({ title, subTitle, btnText }) => {
    const [ open, setOpen ] = useState(false);
    const handleClick = () => {
        setOpen(!open);
    };
    return (
        <AccordionWrapper>
            <h2>{title}</h2>
            <h3>{subTitle}</h3>
            <InternalWrapper open={open}>
                <h1>Hello</h1>
            </InternalWrapper>
            <Button padding="5px" onClick={handleClick}>
                {btnText}
            </Button>
        </AccordionWrapper>
    );
};

Accordion.defaultProps = {
    title    : 'title',
    subTitle : 'subtitle',
    btnText  : 'Read more >>'
};

export default Accordion;

Here is a codepen reproduction. https://codepen.io/hichihachi/pen/MWwKZEO?editors=0010

Any help would be appreciated, thanks.


Solution

  • Max-height transition doesn't work when you set it in percentage and in some other units. To make the transition work you can define something like

    max-height: ${(props) => (props.open ? '100px' : '0')};

    https://codepen.io/alonabas/pen/PoqNYLR?editors=1111

    But if your content is more than 100px in height, when you open the Accordion the content will be cut. In this case you can use jQuery to calculate the exact size of your content or use some maximal possible value of max-height.

    Both options are described here: https://stackoverflow.com/a/8331169/2916925