Panel / Side Panels
Panel Layout
Let’s look how to add Side Panels to our App. We may include up to 2 panels to our App, one on left side and another one on right side. We should add panels’ HTML right in the beginning of the app root element (or in case there is no root element in use):
<body>
<!-- App root element -->
<div id="app">
<!-- Left panel -->
<div class="panel panel-left">
... panel content goes here ...
</div>
<!-- Right panel -->
<div class="panel panel-right">
... panel content goes here ...
</div>
...
</div>
</body>
Panel Effect
After we added panels we need to choose opening effect for each panel. There could be one of two effects: “Reveal” (when panel moves out whole app’s content) or “Cover” (when panel overlays app’s content). If you want to use “Reveal” effect you should add additional **panel-reveal**
class to Panel, or **panel-cover**
for cover effect:
<body>
<!-- App root element -->
<div id="app">
<!-- Left panel, let it be with reveal effect -->
<div class="panel panel-left panel-reveal">
... panel content goes here ...
</div>
<!-- Right panel, with cover effect -->
<div class="panel panel-right panel-cover">
... panel content goes here ...
</div>
...
</div>
</body>
Resizable Panel
Each Panel can be resizable. To make Panel resizable we just need to add panel-resizable
class to Panel element:
<body>
<!-- App root element -->
<div id="app">
<!-- Make left panel resizable -->
<div class="panel panel-left panel-resizable">
... panel content goes here ...
</div>
<!-- Make right panel resizable -->
<div class="panel panel-right panel-resizable">
... panel content goes here ...
</div>
...
</div>
</body>
Panel App Parameters
It is possible to control some default panels behavior using global app parameters by passing panels related parameters under panel
parameter:
Parameter | Type | Default | Description |
---|---|---|---|
leftBreakpoint | number | Minimal app width (in px) when left panel becomes always visible | |
rightBreakpoint | number | Minimal app width (in px) when right panel becomes always visible | |
swipe | string | Disabled by default. If you want to enable ability to open/close side panels with swipe you can pass here left (for left panel) or right (for right panel) or both (for both panels). | |
swipeActiveArea | number | 0 | Width (in px) of invisible edge from the screen that triggers swipe panel |
swipeCloseOpposite | boolean | true | This parameter gives ability to close opposite panel by swipe. For example, if your swipePanel is “left”, then you could close “right” panel also with swipe. |
swipeOnlyClose | boolean | false | This parameter allows to close (but not open) panels with swipes |
swipeNoFollow | boolean | false | Fallback option for potentially better performance on old/slow devices. If you enable it, then side panel will not follow your finger during touch, it will be automatically opened/closed on swipe left/right. |
swipeThreshold | number | 0 | Panel will not move with swipe if “touch distance” will be less than this value (in px). |
closeByBackdropClick | boolean | true | Enable/disable ability to close panel by clicking outside of panel (on panel’s backdrop) |
For example:
var app = new Framework7({
panel: {
swipe: 'left',
leftBreakpoint: 768,
rightBreakpoint: 1440,
}
});
Panel App Methods
Let’s look at related App methods to work with Panel:
app.panel.open(side, animate)- open panel
- side - string. Panel to open: “left” or “right”. Required in case you have two panels.
- animate - boolean. Should it be opened with animation or not. Optional, by default is
true
app.panel.close(side, animate)- close panel
- side - string. Panel to close. Optional, by default will close any opened panel.
- animate - boolean. Should it be closed with animation or not. Optional, by default is
true
app.panel.toggle(side, animate)- toggle panel
- side - string. Panel to toggle. Optional, by default will toggle any opened panel.
- animate - boolean. Should it be opened/closed with animation or not. Optional, by default is
true
app.panel.create(parameters)- create new panel instance
- parameters - object. Object with panel parameters.
Method returns created Panel instance
Use this method only in case you have added panel to DOM after app initialization. Otherwise it will be created automatically
app.panel.get(side)- get Panel instance by specified side
- side - string. Panel to get
Method returns Panel instance
app.panel.enableSwipe(side)- enable swipes for panel (swipe-to-close and swipe-to-open)
- side - string. Panel to enable swipe actions on
app.panel.disableSwipe(side)- disable swipes for panel (swipe-to-close and swipe-to-open)
- side - string. Panel to disable swipe actions on
app.panel.enableResizable(side)- makes specified panel resizable
- side - string. Side of the panel that needs to be resizable
app.panel.disableResizable(side)- disable resizable panel
- side - string. Side of the panel to disable resizing
app.panel.left- left panel instance
app.panel.right- right panel instance
Panel Parameters
If we create Panel manually using app.panel.create
method we need to pass object with panel parameters:
Parameter | Type | Default | Description |
---|---|---|---|
el | HTMLElement | Panel element | |
side | string | Can be left or right . If not passed then will be determined based on panel-left or panel-right element classes | |
effect | string | Can be cover or reveal . If not passed then will be determined based on panel-cover or panel-reveal element classes | |
resizable | boolean | If not passed then will be determined based on panel-resizable class |
For example:
var panel = app.panel.create({
el: '.panel-left',
})
Panel Methods & Properties
After we created Panel instance (by calling app.panel.create
) or after we got Panel instance (by calling app.panel.get
) we may use its useful methods and properties:
Properties | |
---|---|
panel.app | Link to global app instance |
panel.side | String with panel side: left or right |
panel.effect | String with panel effect: cover or reveal |
panel.opened | Boolean property indicating whether it is opened or not |
panel.el | Panel HTML element |
panel.$el | Dom7 instance with panel HTML element |
panel.backdropEl | Backdrop HTML element |
panel.$backdropEl | Dom7 instance with backdrop HTML element |
panel.params | Popup parameters |
Methods | |
panel.open(animate) | Open panel. Where
|
panel.close(animate) | Close panel. Where
|
panel.toggle(animate) | Toggle panel. Where
|
panel.destroy() | Destroy panel instance |
panel.on(event, handler) | Add event handler |
panel.once(event, handler) | Add event handler that will be removed after it was fired |
panel.off(event, handler) | Remove event handler |
panel.off(event) | Remove all handlers for specified event |
panel.emit(event, …args) | Fire event on instance |
Control Panel With Links
It is possible to open and close required panel (if you have them in DOM) using special classes and data attributes on links:
To open panel we need to add
**panel-open**
class to any HTML element (prefered to link)To close panel we need to add
**panel-close**
class to any HTML element (prefered to link)To toggle panel we need to add
**panel-toggle**
class to any HTML element (prefered to link)If you want to specify which panel should opened/closed, then it could be done via additional
**data-panel="left**
attribute on this HTML element
According to above note:
<body>
<div id="app">
<!-- Left Panel with Reveal effect -->
<div class="panel panel-left panel-reveal">
<div class="content-block">
...
<!-- Clicking on link with "panel-close" class will close panel -->
<p><a href="#" class="panel-close">Close me</a></p>
<!-- Click on link with "panel-open" and data-panel="right" attribute will open Right panel -->
<p><a href="#" data-panel="right" class="panel-close">Open Right Panel</a></p>
</div>
</div>
<!-- Right Panel with Cover effect -->
<div class="panel panel-right panel-cover">
<div class="content-block">
...
<!-- Click on link with "panel-close" class will close panel -->
<p><a href="#" class="panel-close">Close me</a></p>
<!-- Click on link with "panel-open" and data-panel="left" attribute will open Left panel -->
<p><a href="#" data-panel="left" class="panel-open">Open Left Panel</a></p>
</div>
</div>
...
<div class="page-content">
<div class="content-block">
<!-- If no data-panel attribute, Left panel will be opened by default -->
<p><a href="#" class="panel-open">Open Left Panel</a></p>
<!-- Click on link with "panel-open" and data-panel="right" attribute will open Right panel -->
<p><a href="#" data-panel="right" class="panel-open">Open Right Panel</a></p>
</div>
</div>
</div>
...
</body>
Routable Panels
Routable Panels available from Framework7 version 3.2.0.
Panels can also be routable with same features as for routable modals and pages:
- it provides opportunity to open Panel by usual links instead of so called special links or API,
- with enabled Push State, the same Panel will be opened when you refresh browser, navigate back and forward in history,
- with routable Panels you can load Panel itself and its content in the same ways as for pages and modals, i.e. using
url
,content
,template
,templateUrl
,component
orcomponentUrl
routes = [
...
// Creates Panel from passed HTML string
{
path: '/left-panel/',
panel: {
content: `
<div class="panel panel-left panel-cover">
<div class="view">
<div class="page">
...
</div>
</div>
</div>
`
}
},
// Load Panel from file via Ajax
{
path: '/right-panel-ajax/',
panel: {
url: './right-panel.html',
/* right-panel.html contains:
<div class="panel panel-right panel-reveal">
<div class="view">
<div class="page">
...
</div>
</div>
</div>
*/
},
},
// Load Panel from component file
{
path: '/panel-component/',
panel: {
componentUrl: './panel-component.html',
/* panel-component.html contains:
<template>
<div class="panel panel-left panel-cover">
<div class="view">
<div class="page">
...
</div>
</div>
</div>
</template>
<style>...</style>
<script>...</script>
*/
},
},
]
According to example above:
- when you click on link with
/left-panel/
href attribute it will open Panel from specified string content, - when you click on link with
/right-panel-ajax/
href attribute it will perform Ajax request toright-panel.html
file and open it as a Right Panel, - when you click on link with
/panel-component/
href attribute it will perform Ajax request topanel-component.html
file, parse it as a Router Component and open it as a Panel,
Note that routable Panels can’t be mixed with static Panels. So if you have static left panel in the app, then only right panel can be loaded as routable panel.
Panel Events
Panel will fire the following DOM events on panel element and events on app and panel instance:
DOM Events
Event | Target | Description |
---|---|---|
panel:open | Panel Element<div class=”panel”> | Event will be triggered when Panel starts its opening animation |
panel:opened | Panel Element<div class=”panel”> | Event will be triggered after Panel completes its opening animation |
panel:close | Panel Element<div class=”panel”> | Event will be triggered when Panel starts its closing animation |
panel:closed | Panel Element<div class=”panel”> | Event will be triggered after Panel completes its closing animation |
panel:backdrop-click | Panel Overlay Element<div class=”panel-backdrop”> | Event will be triggered when the panel overlay is clicked |
panel:swipeopen | Panel Element<div class=”panel”> | Event will be triggered in the very beginning of opening it with swipe |
panel:swipe | Panel Element<div class=”panel”> | Event will be triggered for swipe panel during touch swipe action |
panel:breakpoint | Panel Element<div class=”panel”> | Event will be triggered when it becomes visible/hidden when app width matches its breakpoint |
panel:resize | Panel Element<div class=”panel”> | Event will be triggered on resizable panel resize |
panel:beforedestroy | Panel Element<div class=”panel”> | Event will be triggered right before Panel instance will be destroyed |
App and Panel Instance Events
Panel instance emits events on both self instance and app instance. App instance events has same names prefixed with panel
.
Event | Target | Arguments | Description |
---|---|---|---|
open | panel | (panel) | Event will be triggered when Panel starts its opening animation. As an argument event handler receives panel instance |
panelOpen | app | (panel) | |
opened | panel | (panel) | Event will be triggered when Panel completes its opening animation. As an argument event handler receives panel instance |
panelOpened | app | (panel) | |
close | panel | (panel) | Event will be triggered when Panel starts its closing animation. As an argument event handler receives panel instance |
panelClose | app | (panel) | |
closed | panel | (panel) | Event will be triggered when Panel completes its closing animation. As an argument event handler receives panel instance |
panelClosed | app | (panel) | |
backdropClick | panel | (panel) | Event will be triggered when the panel backdrop is clicked. As an argument event handler receives panel instance |
panelBackdropClick | app | (panel) | |
swipeOpen | panel | (panel) | Event will be triggered in the very beginning of opening it with swipe. As an argument event handler receives panel instance |
panelSwipeOpen | app | (panel) | |
swipe | panel | (panel, progress) | Event will be triggered for swipe panel during touch swipe action. As an argument event handler receives panel instance and opened progress (from 0 to 1) |
panelSwipe | app | (panel, progress) | |
breakpoint | panel | (panel) | Event will be triggered when it becomes visible/hidden when app width matches its breakpoint. As an argument event handler receives panel instance |
panelBreakpoint | app | (panel) | |
resize | panel | (panel, newPanelWidth) | Event will be triggered on resizable panel resize |
panelResize | app | (panel) | |
beforeDestroy | panel | (panel) | Event will be triggered right before Panel instance will be destroyed |
panelBeforeDestroy | app | (panel) |
CSS Variables
Below is the list of related CSS variables (CSS custom properties).
Note that commented variables are not specified by default and their values is what they fallback to in this case.
:root {
--f7-panel-width: 260px;
/*
--f7-panel-left-width: var(--f7-panel-width);
--f7-panel-right-width: var(--f7-panel-width);
*/
--f7-panel-bg-color: #fff;
}
.ios {
--f7-panel-backdrop-bg-color: rgba(0, 0, 0, 0);
--f7-panel-transition-duration: 400ms;
--f7-panel-shadow: transparent;
}
.md {
--f7-panel-backdrop-bg-color: rgba(0, 0, 0, 0.2);
--f7-panel-transition-duration: 300ms;
--f7-panel-shadow: rgba(0, 0, 0, 0.25) 0%,
rgba(0, 0, 0, 0.1) 30%,
rgba(0, 0, 0, 0.05) 40%,
rgba(0, 0, 0, 0) 60%,
rgba(0, 0, 0, 0) 100%;
}
.aurora {
--f7-panel-backdrop-bg-color: rgba(0, 0, 0, 0.2);
--f7-panel-transition-duration: 400ms;
--f7-panel-shadow: transparent;
}
Examples
<body>
<div id="app">
<div class="panel panel-left panel-reveal panel-resizable">
<div class="block">
<p>Left Panel content here</p>
<p><a class="panel-close" href="#">Close me</a></p>
<p><a class="panel-open" href="#" data-panel="right">Open Right Panel</a></p>
</div>
</div>
<div class="panel panel-right panel-cover panel-resizable">
<div class="block">
<p>Right Panel content here</p>
<p><a class="panel-close" href="#">Close me</a></p>
<p><a class="panel-open" href="#" data-panel="left">Open Left Panel</a></p>
</div>
</div>
<div class="view view-main view-init">
<div class="page">
<div class="navbar">
<div class="navbar-inner">
<div class="left"></div>
<div class="title">Panels</div>
<div class="right"></div>
</div>
</div>
<div class="page-content">
<div class="block">
<p><a class="panel-open" href="#">Open Left Panel</a></p>
<p><a class="panel-open" href="#" data-panel="right">Open Right Panel</a></p>
</div>
</div>
</div>
</div>
</div>
</body>
/* Limit resizable panel width */
.panel {
min-width: 100px;
max-width: 90vw;
}
var app = new Framework7();
var $$ = Dom7;
// Dom Events
$$('.panel-left').on('panel:open', function () {
console.log('Panel left: open');
});
$$('.panel-left').on('panel:opened', function () {
console.log('Panel left: opened');
});
// Instance Events
var panelRight = app.panel.right;
panelRight.on('open', function () {
console.log('Panel right: open');
});
panelRight.on('opened', function () {
console.log('Panel right: opened');
});
// App Events
app.on('panelClose', function (panel) {
console.log('Panel ' + panel.side + ': close');
});
app.on('panelClosed', function (panel) {
console.log('Panel ' + panel.side + ': closed');
});
app.on('panelResize', function (panel, newPanelWidth) {
console.log('Panel resized to ' + newPanelWidth + 'px');
});