Reputation: 11
I'm a Junior developer, this is my first question here
I'm using a Controlled accordion because I need the icon to change dynamically but I want it to stay open when I expand a panel, even if I have expanded another panel like the basic does.
I understand that it has to do with the handleChange function but its logic is beyond me for now
I'm working with React
Any ideas ?
const [expanded, setExpanded] = React.useState(false);
const handleChange = (panel) => (event, isExpanded) => {
setExpanded(isExpanded ? panel : false);
};
{grant?.generalRequirementsDetails.length ? (
<div className="grant-info-items">
<MuiAccordion
expanded={expanded === 'panel1'}
onChange={handleChange('panel1')}
>
<AccordionSummary
expandIcon={
expanded ? (
<img src={lessSVG} alt="less" />
) : (
<img src={moreSVG} alt="more" />
)
}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<h3 sx={{ width: '33%', flexShrink: 0 }}>
Requisitos generales
</h3>
</AccordionSummary>
<AccordionDetails>
{grant?.generalRequirementsDetails.map(
(item, idx) => (
<div key={idx} className="grant-item">
<img src={tickSVG} />
<p>{item}</p>
</div>
),
)}
</AccordionDetails>
</MuiAccordion>
</div>
) : null}
I have another couple of panels similar to this one so when I click on one and then another I want both to be open unless I click on one of them again and that panel collapses like in the basic accordion
here is the link of the MUI component i'm talking about: https://mui.com/components/accordion/
Thank you for your help !
Upvotes: 1
Views: 2253
Reputation: 7447
It looks like the accordion panels are controlled by a single state for opening and closing, therefore if one is opening the others are closed.
You could make each accordion a separate component so each will have its own expanded
state. Alternatively, use an object state to store a expanded
status for each accordion panel separately.
Minimal demo for both examples: stackblitz
Example for making each accordion a separate component:
export const MyPanel = ({ grant }) => {
const [expanded, setExpanded] = React.useState(false);
const handleChange = () => setExpanded((prev) => !prev);
return (
<Accordion expanded={expanded} onChange={handleChange}>
<AccordionSummary
expandIcon={expanded ? <RemoveIcon /> : <AddIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
</AccordionSummary>
<AccordionDetails>
{grant?.generalRequirementsDetails.map((item, idx) => (
<div key={idx} className="grant-item">
<p>{`generalRequirementsDetails: ${item}`}</p>
</div>
))}
</AccordionDetails>
</Accordion>
);
};
export default function App() {
return (
<div>
{grant?.generalRequirementsDetails.length ? (
<div className="grant-info-items">
{[0, 1, 2].map((item) => {
return <MyPanel key={item} grant={grant} />;
})}
</div>
) : null}
</div>
);
}
Example for using an object state for controls:
export default function App() {
const [expanded, setExpanded] = React.useState({});
const handleChange = (panel) => () => {
setExpanded((prev) => {
return { ...prev, [panel]: !!!prev[panel] };
});
};
return (
<div>
{grant?.generalRequirementsDetails.length ? (
<div className="grant-info-items">
<Accordion
expanded={!!expanded['panel1']}
onChange={handleChange('panel1')}
>
<AccordionSummary
expandIcon={!!expanded['panel1'] ? <RemoveIcon /> : <AddIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
</AccordionSummary>
<AccordionDetails>
{grant?.generalRequirementsDetails.map((item, idx) => (
<div key={idx} className="grant-item">
<p>{`generalRequirementsDetails: ${item}`}</p>
</div>
))}
</AccordionDetails>
</Accordion>
<Accordion
expanded={!!expanded['panel2']}
onChange={handleChange('panel2')}
>
<AccordionSummary
expandIcon={!!expanded['panel2'] ? <RemoveIcon /> : <AddIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
</AccordionSummary>
<AccordionDetails>
{grant?.generalRequirementsDetails.map((item, idx) => (
<div key={idx} className="grant-item">
<p>{`generalRequirementsDetails: ${item}`}</p>
</div>
))}
</AccordionDetails>
</Accordion>
<Accordion
expanded={!!expanded['panel3']}
onChange={handleChange('panel3')}
>
<AccordionSummary
expandIcon={!!expanded['panel3'] ? <RemoveIcon /> : <AddIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
</AccordionSummary>
<AccordionDetails>
{grant?.generalRequirementsDetails.map((item, idx) => (
<div key={idx} className="grant-item">
<p>{`generalRequirementsDetails: ${item}`}</p>
</div>
))}
</AccordionDetails>
</Accordion>
</div>
) : null}
</div>
);
}
Upvotes: 1