Material-UI: Expand Accordion by clicking the icon only
Asked Answered
A

6

12

I have created an Accordion for my Project. But I want the panel to be expanded only when the expand icon is clicked. Currently it is expanding on clicking anywhere on the panel. Can we customize its expanding behavior ?

CODE:

import React from "react";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import Accordion from "@material-ui/core/Accordion";
import AccordionDetails from "@material-ui/core/AccordionDetails";
import Typography from "@material-ui/core/Typography";
import AccordionSummary from "@material-ui/core/AccordionSummary";

export default function App() {
return (
    <div style={{}}>
    <h4>How to create Accordion in ReactJS?</h4>
    <Accordion style={{ width: 400}}>
        <AccordionSummary 
         expandIcon={<ExpandMoreIcon />}
         aria-controls="panel1a-content"
        >   
          <div>Click to Expand</div>
        </AccordionSummary>
        <AccordionDetails>
        <Typography>Greetings of the day :)</Typography>
        </AccordionDetails>
    </Accordion>
    </div>
);
}
Azelea answered 28/9, 2021 at 9:5 Comment(0)
L
14

Yes we can do it like this

1- Create our own state with handler:

  const [expand, setExpand] = React.useState(false);
  const toggleAcordion = () => {
    setExpand((prev) => !prev);
  };

2- Add our state to the Accordion:

<Accordion expanded={expand} style={{ width: 400 }}>

3- Add onClick for the icon:

    <AccordionSummary
      expandIcon={<ExpandMoreIcon />}
      aria-controls="panel1a-content"
      IconButtonProps={{
        onClick: toggleAcordion
      }}
    >

Full Code:

Codesandbox Demo

EDIT: Explanation: Material-UI Accordion has its own state (open or close) and its own click handler, what we did above is that we create our own state and override Material-UI Accordion state by the prop expanded and add event listener onClick to the icon button by the prop IconButtonProps, our event listener will open or close the Accordion by change our state.

NOTE: The code above doesn't change the style in case of the cursor pointer.

Longobard answered 28/9, 2021 at 9:24 Comment(4)
Thanks a lot.. It worked !!! Can you please give an explanation of how it is working..Azelea
@Azelea sure, I added explanation to the answer, I hope it's clear for you.Longobard
got it.. Thanks..Azelea
For v5, see my answerAccordingly
S
13

There is no public API to do what you want out-of-the-box, but you can use this CSS trick:

V5

<AccordionSummary
  sx={{
    pointerEvents: "none"
  }}
  expandIcon={
    <ExpandMoreIcon
      sx={{
        pointerEvents: "auto"
      }}
    />
  }
>

V4

const useStyles = makeStyles({
  summary: {
    pointerEvents: 'none',
  },
  icon: {
    pointerEvents: 'auto',
  },
});
<AccordionSummary
  className={classes.summary}
  expandIcon={<ExpandMoreIcon className={classes.icon} />}
>
  <Typography>Accordion 1</Typography>
</AccordionSummary>

Live Demo

Codesandbox Demo

Storer answered 28/9, 2021 at 9:18 Comment(2)
We have API, check this out v4.mui.com/api/accordion-summary and v4.mui.com/api/accordionLongobard
What I meant is that there is not a simple prop like expandOnButtonClick, but yeah, it's doable if you control the Accordion state, I'll edit my answer. @LongobardStorer
A
6

For v5, and setting the mouse cursor properly:

1- Create our own state with handler:

const [accordionOpen, setAccordionOpen] = React.useState(false);

2- Add our state to the Accordion and toggle on click:

<Accordion expanded={accordionOpen}>
    <AccordionSummary
      expandIcon={
        <ExpandMoreIcon
          style={{ cursor: 'pointer' }}
          onClick={() => setAccordionOpen(!accordionOpen)} />
      }
      sx={{ cursor: 'unset !important' }}
    >
Accordingly answered 22/10, 2022 at 23:50 Comment(1)
So one needs this hack to add on change on icon? Can you elaborate more on how and why your solution works please?Gerdes
D
2

None of these solutions worked for me. I handled it with the e.stopPropagation() method, using it in the onClick event of the icon after calling the toggle function.

Like this:

import React from "react";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import Accordion from "@material-ui/core/Accordion";
import AccordionDetails from "@material-ui/core/AccordionDetails";
import Typography from "@material-ui/core/Typography";
import AccordionSummary from "@material-ui/core/AccordionSummary";

export default function App() {
return (
    <div style={{}}>
    <h4>How to create Accordion in ReactJS?</h4>
    <Accordion style={{ width: 400}}>
        <AccordionSummary 
         expandIcon={<ExpandMoreIcon />}
         aria-controls="panel1a-content"
        >   
          <div ><img src='yourIcon' onClick={(e) => { toggleAccordion(); e.stopPropagation() }} /></div>
        </AccordionSummary>
        <AccordionDetails>
        <Typography>Greetings of the day :)</Typography>
        </AccordionDetails>
    </Accordion>
    </div>
);
}
Dubitable answered 1/2, 2023 at 10:52 Comment(0)
M
1

you can try set expanded true/false in the Accordion

function Container(props) {
  const [expand, setExpand] = React.useState(false);
  const toggleAccordion = () => {
    setExpand((prev) => !prev);
  };
  return (
    <React.Fragment>
      <Accordion expanded={expand}>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon
            onClick={toggleAccordion}
          />}
          aria-controls="panel1a-content"
          id="panel1a-header"
        >
          <Typography></Typography>
        </AccordionSummary>
        <AccordionDetails>
        </AccordionDetails>
      </Accordion>
    </React.Fragment>)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Moulder answered 22/11, 2022 at 1:47 Comment(0)
E
0

I solved it in this way using the onChange property in Accordion (TS version):

interface Props {
  data: {id: number, name: string, detail: string}
}
const YourComponent: React.FC<Props> = ({ data }) => {
  const [expanded, setExpanded] = useState<number | false>(false) 

  const handleExpand = (id: number) => (_e: React.SyntheticEvent, isExpanded: boolean) => {
  setExpanded(isExpanded ? id : false)
}

return (
  <>
    <Accordion expanded={expanded === data.id} onChange={handleExpand(data.id)}>
      <AccordionSummary
        expandIcon={<ExpandMoreIcon/>}
      >
        {data.name}
      </AccordionSummary>
      <AccordionDetails>
        {data.detail}
      </AccordionDetails>
    </Accordion>
  </>
 )
}
Engle answered 20/3 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.