2

I aim to create a custom Material UI accordion which should look like this: Accordion aim look

Now, I have attempted in creating this custom MUI accordion using these code structure (this accordion also uses some custom search box functionality and custom accordion data)

Accordion source code:

import * as React from "react";
import { useState } from "react";
import AccordionMUI from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import Typography from "@mui/material/Typography";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import "./globals.css";
import { accordionData } from "./accordionData.js";
import AddCircleIcon from "@mui/icons-material/AddCircle";
import RemoveCircleIcon from "@mui/icons-material/RemoveCircle";


export default function SimpleAccordion() {
  const [search, setSearch] = useState("");
  return (
    <div>
      <input
        onChange={(e) => setSearch(e.target.value)}
        type="text"
        placeholder="Search"
      />

      {accordionData
        .filter((item) => {
          return search.toLowerCase() === ""
            ? item
            : item.sectionTitle.toLowerCase().includes(search);
        })
        .map((item) => (
          <AccordionMUI key={item.id} className="accordionMui">
            <AccordionSummary
              expandIcon={<AddCircleIcon sx={{ color: "#384558" }} />}
              aria-controls="panel1a-content"
              id="panel1a-header"
            >
              <Typography>
                <b>{item.sectionTitle}</b>
              </Typography>
            </AccordionSummary>
            <AccordionDetails>
              <Typography>{item.sectionContent}</Typography>
            </AccordionDetails>
          </AccordionMUI>
        ))}
    </div>
  );
}

CSS styling source code:

.accordionMui {
  background-color: rgba(242, 242, 242, 0.1);
  box-shadow: none;
  color: #384558;
}

#panel1a-header {
  padding-top: 5%;
  padding-bottom: 5%;
}

Full working demo here on CodeSandbox.

It currently looks like this: current look accordion

My issue is that the last divider line of my accordion is not showing up unlike from its previous sections where there is a divider line on them below. I also want to override the styling of the divider line of the accordion and make it thicker.

I also wanted to change the collapse icons into their respective states (not expanded accordion will display AddCircleIcon, expanded accordion will display RemoveCircleIcon) but a problem arises which shows Cannot find name 'expanded' when I use this ternary condition expanded={expanded === 'panel1'} just like from this stack accepted question (How to change icon when accordion summary is expanded?). Thus, I am not sure how to change the collapse icons based from their states of being expanded or not expanded yet.

I am still quite confused and unsure on which classes I should use on the Accordion API of MUI and it would be of great help to gain some guides in regards to properly customizing and overriding the Accordion component from MUI as I am still learning MUI along the way.

Your responses would indeed help me a lot on this one. Thank you very much.

Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
Ralph Henry
  • 122
  • 1
  • 13

2 Answers2

1

You could do like this:

  1. Change to a different icon when expanded:

just like from this stack accepted question (How to change icon when accordion summary is expanded?). Thus, I am not sure how to change the collapse icons based from their states of being expanded or not expanded yet.

-> As per the mui accordion documentation and the way of doing in the stack question is almost same:

You need to set state to handle AccordionMUI and control by using icons.

...
  const [expanded, setExpanded] = React.useState(false);
  const handleChange = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };
...
  <AccordionMUI
     key={item.id}
    //set unique item id for each accordion
     expanded={expanded === item.id}
     onChange={handleChange(item.id)}
     className="accordionMui"
  >
  <AccordionSummary
     expandIcon={
     expanded === item.id ? <RemoveCircleIcon /> : 
     <AddCircleIcon />
     } 
  >
  ...
...
  1. Make divider line thicker & Missing divider line

--> You need to remove this: (to show background color instead of box-shadow)

box-shadow: none;

Updated demo:

Edit BasicAccordion demo — Material UI (forked)

I hope this helps!

nuser137
  • 401
  • 2
  • 8
  • 1
    Very good implementation @nuser137, my only concern is that when a collapse icon is clicked, all the sections seemed to also collapse simultaneously from your codesandbox, which shouldn't be the case. Only one accordion section only needs to be collapsed per click on a collapse icon. Would like to ask for any logic tweaks on your conditionals. – Ralph Henry May 27 '23 at 18:23
  • Yes, absolutely you are correct, as when I post my answer and double checked it if it working as expected or not so, I was also surprised that it wasnt working, expanding all accordion section at a time. ... I was acutally checking this right now when you posted your comment ;) Hopefully I'll try my best to solve it and update it soon!! (for now I am removing codesand box link if updated I'll update it) – nuser137 May 27 '23 at 18:26
  • nice nice, will look forward for any updates on your codesandbox as this would definitely help me a lot @nuser137 – Ralph Henry May 27 '23 at 18:28
  • 1
    Hi, All issues get solved!! You can check it out, if everything is working or not? – nuser137 May 27 '23 at 18:36
  • 1
    Splendid work @nuser137!!! Thank you very much for your active and consistent guides and help. You are the best! Let's keep learning and growing! – Ralph Henry May 27 '23 at 18:44
  • 1
    Yes, well I am just learning next.js for my new project – nuser137 May 27 '23 at 18:46
  • 1
    Same here about next.js @nuser137, along with typescript! Do well on your works! – Ralph Henry May 27 '23 at 18:47
  • 1
    Thank you so much!! for giving me well wishes. – nuser137 May 27 '23 at 18:48
1

Great question.

The Accordion component is a MUI-opinionated Collapse component. Perhaps instead of trying to wrangle Accordion, how about making a custom component using Collapse?

CodeSandbox Example

function CustomAccordion(props) {
  const { data } = props
  const [isOpen, setIsOpen] = useState(true)

  return (
    <>
      <Box
        display="flex"
        justifyContent="space-between"
        height="60px"
        alignItems="center"
      >
        <Box sx={{ fontWeight: 'bold' }}>{data.title}</Box>
        <IconButton onClick={() => setIsOpen(!isOpen)}>
          {isOpen ? <AddCircle /> : <RemoveCircle />}
        </IconButton>
      </Box>
      <Collapse in={!isOpen} sx={{textAlign: 'left'}}>
        {data.content}
      </Collapse>
      <Divider />
    </>
  )
}

export default CustomAccordion
ckesplin
  • 1,284
  • 1
  • 9
  • 15
  • Great implementation @ckesplin!! Will definitely consider this as one of my approaches when it comes to creating accordions! Thank you very much for your response @ckesplin – Ralph Henry May 27 '23 at 19:44