An unopinionated, zero-dependency panel and accordion
ember install ember-collapsible-panel
The 2.x series of Collapsible Panels relies on contextual components, a feature introduced in Ember 2.3.
If your app is on a version < 2.3, install the 1.0 version of this library (with ember install ember-collapsible-panel@1.0
).
You can optionally install Liquid Fire for animation support. For more details, see Animation.
{{#cp-panel as |p|}}
{{#p.toggle}}
<p>Click me!</p>
{{/p.toggle}}
{{#p.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus neque magnam, hic quis beatae repellendus harum modi pariatur minus quidem alias! Eius incidunt impedit eaque, est, illo officiis expedita molestiae.</p>
</div>
{{/p.body}}
{{/cp-panel}}
{{#cp-panel open=true as |p|}}
{{#p.toggle}}
<p>Click me!</p>
{{/p.toggle}}
{{#p.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus neque magnam, hic quis beatae repellendus harum modi pariatur minus quidem alias! Eius incidunt impedit eaque, est, illo officiis expedita molestiae.</p>
</div>
{{/p.body}}
{{/cp-panel}}
Click me!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus neque magnam, hic quis beatae repellendus harum modi pariatur minus quidem alias! Eius incidunt impedit eaque, est, illo officiis expedita molestiae.
Wrap a list of panels in a cp-panels
component with accordion=true
:
{{#cp-panels accordion=true as |panels|}}
{{#panels.panel as |panel|}}
{{#panel.toggle}}
<p>Panel A</p>
{{/panel.toggle}}
{{#panel.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus neque magnam, hic quis beatae repellendus harum modi pariatur minus quidem alias! Eius incidunt impedit eaque, est, illo officiis expedita molestiae.</p>
</div>
{{/panel.body}}
{{/panels.panel}}
{{#panels.panel as |panel|}}
{{#panel.toggle}}
<p>Panel B</p>
{{/panel.toggle}}
{{#panel.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus neque magnam, hic quis beatae repellendus harum modi pariatur minus quidem alias! Eius incidunt impedit eaque, est, illo officiis expedita molestiae.</p>
</div>
{{/panel.body}}
{{/panels.panel}}
{{/cp-panels}}
You can put sibling cp-panel
s (or a cp-panels
wrapper) in the body of a parent panel:
{{#cp-panel as |p|}}
{{#p.toggle}}
<p>Parent</p>
{{/p.toggle}}
{{#p.body}}
{{#cp-panels class='u-margin-bottom' accordion=true as |panels|}}
{{#panels.panel as |p|}}
{{#p.toggle}}
<p>Child 1</p>
{{/p.toggle}}
{{#p.body}}
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cupiditate veniam facere consectetur, aperiam nostrum, praesentium nisi. Quae fuga, maiores, hic atque velit, omnis explicabo dolore a quaerat, harum perferendis voluptate.</p>
{{/p.body}}
{{/panels.panel}}
{{#panels.panel as |p|}}
{{#p.toggle}}
<p>Child 2</p>
{{/p.toggle}}
{{#p.body}}
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cupiditate veniam facere consectetur, aperiam nostrum, praesentium nisi. Quae fuga, maiores, hic atque velit, omnis explicabo dolore a quaerat, harum perferendis voluptate.</p>
{{/p.body}}
{{/panels.panel}}
{{/cp-panels}}
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repellat error enim, quae pariatur atque possimus aliquam, beatae saepe veritatis natus alias nostrum! Atque aliquid, fugit esse dolor ducimus. Ab, labore.</p>
{{/p.body}}
{{/cp-panel}}
Sometimes, you need more control over your panels. If you have many panels, managing each panel's state can get complex.
To save you the trouble, we've brought along a panelActions
service, which can manage the state of your panels, and gives you a nice API for interacting with them.
Now, other components in your UI can open and close panels without the need for you to pass around actions or manage state. It's like the simplicity of $('.panel').toggle()
, without any of the downsides!
export default Ember.Component.extend({
panelActions: Ember.inject.service(),
actions: {
expandAll() {
this.get('panelActions').openAll('group1');
},
collapseAll() {
this.get('panelActions').closeAll('group1');
},
togglePanelA() {
this.get('panelActions').toggle('panelA');
},
togglePanelB() {
this.get('panelActions').toggle('panelB');
},
}
});
<div class="u-margin-bottom">
<button class='btn btn-default' {{action 'expandAll'}}>Expand All</button>
<button class='btn btn-default' {{action 'collapseAll'}}>Collapse All</button>
<button class='btn btn-default' {{action 'togglePanelA'}}>Toggle Panel A</button>
<button class='btn btn-default' {{action 'togglePanelB'}}>Toggle Panel B</button>
</div>
{{#cp-panels name='group1' as |panels|}}
{{#panels.panel name='panelA' as |p|}}
{{#p.toggle}}
<p>Panel A</p>
{{/p.toggle}}
{{#p.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
</div>
{{/p.body}}
{{/panels.panel}}
{{#panels.panel name='panelB' as |p|}}
{{#p.toggle}}
<p>Panel B</p>
{{/p.toggle}}
{{#p.body}}
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nemo repellendus nisi asperiores esse aperiam aliquid nulla ad dolor autem neque, nihil inventore temporibus delectus earum facere corporis, quam ipsum maxime.</p>
</div>
{{/p.body}}
{{/panels.panel}}
{{/cp-panels}}
If Liquid Fire is installed, animations will automatically be enabled.
Panels will use the crossFade
transition included in Liquid Fire.
To disable animations, add animate: false
to a cp-panel
The class names of the structure of a panel are shown to the right.
Panel body content is only rendered if the panel is open.
The panel, toggle and body all get the `cp-is-open` class when the panel is open. This is so you can style each piece based on the state of the panel - descendent selectors can get tricky since you can nest panels.
Finally, if you want to add padding to the body, target `.cp-Panel-body-inner`. Changing the height of the `.cp-Panel-body` itself will interfere with the animation.
Sample styling
Here's the default markup and styling used for the panels in this site:
<!-- closed panel --> <div class='cp-Panel'> <a href='#' class='cp-Panel-toggle'> </a> <div class='cp-Panel-body'> <!-- content is not rendered --> </div> </div> <!-- open panel --> <div class='cp-Panel cp-is-open'> <a href='#' class='cp-Panel-toggle cp-is-open'> </a> <div class='cp-Panel-body cp-is-open'> <div class='cp-Panel-body-inner'> </div> </div> </div>
.cp-Panel {
border: 1px solid #ddd;
}
.cp-Panel-toggle {
display: block;
padding: 1em;
}
.cp-Panel-toggle:link {
text-decoration: none;
}
.cp-Panel-toggle:hover {
background-color: whitesmoke;
}
.cp-Panel-body-inner {
padding: 1em;
}