Reputation: 145
I'm currently working on an accordion component in react version 16.3.2, that receives props from another component and displays the accordion accordingly. Unfortunately I cannot use hooks.
This works pretty smoothly, what I want to implement now is a way so that only one accordion can be opened at the same time on the same page. So, once you open one accordion (while another is already opened) it should automatically close the already opened one.
I have an Id (string which describes the current section, e.g 'contact', 'info', etc.) and the state of an accordion gets saved in the state (set to true when you toggle the accordion). I'm not quite sure on how I could implement this mechanism and am looking for tips on how I could solve this in a smart way. Any pointers?
example: https://codesandbox.io/s/reactjs-accordion-automatic-close-mechanism-6dys1 (I didn't add all of the styling, animations since this is more about functionality)
Upvotes: 1
Views: 7173
Reputation: 874
You could do something like this, using the state hook in the App component
export default function App() {
const items = [
{ id: 1, title: 'First Accordion', content: 'Hello' },
{ id: 2, title: 'Click me', content: 'Hello 2' },
{ id: 3, title: 'Third Accordion Accordion', content: 'Hello 3' },
]
const [selectedItem, setSelectedItem] = useState(1)
const handleClick = id => {
setSelectedItem(id)
}
return (
<div className="App">
{items.map(x => {
return (
<Accordion
key={x.id}
id={x.id}
title={x.title}
open={x.id === selectedItem}
onClick={handleClick}
>
<p>{x.title}</p>
</Accordion>
)
})}
</div>
);
}
Then your accordion component is a bit simpler
class Accordion extends React.Component {
accToggle() {
this.props.onClick(this.props.id);
}
sectionClasses() {
let classes = "accordion";
classes += this.props.open ? " sec-on" : "";
classes += "sec-underway";
return classes.trim();
}
render() {
return (
<section className={this.sectionClasses()} id={this.props.id}>
<div className="acc-title" onClick={this.accToggle.bind(this)}>
<h3 className="acc-text">{this.props.title}</h3>
<div className="acc-nav">
<span className="acc-toggle" />
</div>
</div>
<div className="acc-content">{this.props.children}</div>
</section>
);
}
}
Accordion.defaultProps = {
open: false
};
Accordion.propTypes = {
id: PropTypes.number.isRequired,
children: PropTypes.any,
onFocus: PropTypes.func,
progress: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool
]),
title: PropTypes.string,
open: PropTypes.bool
};
export default Accordion;
The accordion calls a function on the app component, which updates the state and the display logic is passed down in the props
Upvotes: 3
Reputation: 4394
You can find solution for your problem in the following codesandbox https://codesandbox.io/s/reactjs-accordion-automatic-close-mechanism-yejc0
Change prop names as it fits your code base, but the logic is solid
Upvotes: 1