Panel Widgetversion added: 1.3
Description: Creates a panel widget
Panels are designed to be as flexible as possible to make it easy to create menus, collapsible columns, drawers, inspectors panes and more.
Where panel markup goes in a page
A panel must be a sibling to the header, content, and footer elements inside a jQuery Mobile page. You can add the panel markup either before or after these elements, but not in between.
Here is an example of the panel before the header, content and footer in the source order:
<div data-role="page"> <div data-role="panel" id="mypanel"> <!-- panel content goes here --> </div><!-- /panel --> <!-- header --> <!-- content --> <!-- footer --> </div><!-- page -->
Alternately, it's possible to add the panel markup after the header, content and footer in the source order, just before the end of the page container. Where in the source order you place the panel markup will depend on how you want to page content to read for people experiencing the page in a C-grade device (HTML only) or for a screen reader.
If a page contains a panel the framework wraps the header, content and footer sections in a div
. When opening a panel with display mode "reveal" or "push" the transition is applied to this wrapper. An exception is fixed headers and footers. Those are not included in the wrapper, but will transition in sync with it. Be aware of the fact that all your visible page content should live inside those page sections.
CSS Multi-column Layout
To avoid blinks when opening a panel, we force hardware acceleration on WebKit browsers. The CSS that is used to do this can cause issues with buttons and form elements on the page if their container has a CSS multi-column layout (column-count
). To resolve this you have to set the following rule for the element or its container:
-webkit-transform: translate3d( 0, 0, 0 );
External Panels
Since jQuery Mobile 1.4.0, it is also possible to have external panels. This means that you can now have panels located outside the page. Panels outside of a page must be initalized manually and will not be handled by auto init. Panels outside of pages will remain in the DOM (unless manually removed) as long as you use Ajax navigation, and can be opened or closed from any page. This can be handy when you want to use the same panel on more than one page.
Here is an example of an external panel:
<div data-role="page"> <!-- header --> <!-- content --> <!-- footer --> </div><!-- page --> <div data-role="panel" id="mypanel"> <!-- panel content goes here --> </div><!-- /panel -->
The panel can be enhanced manually as follows:
$( function() { $( "#mypanel" ).panel(); } );
Note that if the panel contains other jQuery Mobile widgets, such as listviews, these will need to be enhanced manually as well.
Panel markup conventions
A panel consists of a container with a data-role="panel"
attribute and a unique ID
. This ID
will be referenced by the link or button to open and close the panel. The most basic panel markup looks like this:
<div data-role="panel" id="mypanel"> <!-- panel content goes here --> </div>
The position of the panel on the screen is set by the data-position
attribute. The position defaults to left
, meaning it will appear from the left edge of the screen. Specify data-position="right"
for it to appear from the right edge instead.
The display mode of the panel is set by the data-display
attribute. The defaults to reveal
, meaning the panel will sit under the page and reveal as the page slides away. Specify data-display="overlay"
for the panel to appear on top of the page contents. A third mode, data-display="push"
animates both the panel and page at the same time.
Here is an example of a panel with a custom position and display option set:
<div data-role="panel" id="mypanel" data-position="right" data-display="push"> <!-- panel content goes here --> </div>
Dynamic content
When you dynamically add content to a panel or make hidden content visible while the panel is open, you have to trigger the updatelayout
event on the panel.
$( "#mypanel" ).trigger( "updatelayout" );
The framework will check the new height of the panel contents and, in case this exceeds the screen height, set the page min-height
to this height and unfix panels with data-position-fixed="true"
. See also Panel positioning.
Opening a panel
A panel's visibility is toggled by a link somewhere on the page or by calling the panel's open
method directly. The defaults place the panel on the left in "reveal" mode. Open a panel programmatically like this:
$( "#idofpanel" ).panel( "open" , optionsHash );
To control a panel from a link, point the href
to the ID
of the panel you want to toggle (mypanel
in the example below). This instructs the framework to bind the link to the panel. This link will toggle the visibility of the panel so tapping it will open the panel, and tapping it again will close it.
<a href="#mypanel">Open panel</a>
When using markup to control panels, you can only have a single panel open at once. Clicking a link to open a panel while one is already open will auto-close the first. This is done to keep the markup-only configuration simple.
Closing a panel
Clicking the link that opened the panel, swiping left or right, or tapping the Esc key will close the panel. To turn off the swipe-to-close behavior, add the data-swipe-close="false"
attribute to the panel.
By default, panels can also be closed by clicking outside the panel onto the page contents. To prevent this behavior, add the data-dismissible="false"
attribute to the panel. It's possible to have the panel and page sit side-by-side at wider screen widths and prevent the click-out-to-close behavior only above a certain screen width by applying a media query. See the responsive section below for details.
A panel can also be closed by calling the panel's close
method directly.
$( "#idofpanel" ).panel( "close" );
It's common to also add a close button inside the panel. To add the link that will close the panel, add the data-rel="close"
attribute to tell the framework to close that panel when clicked. It's important to ensure that this link also makes sense if JavaScript isn't available, so we recommend that the href
points to the ID of the page to which the user should jump when closing. For example, if the button to open the panel is in the header bar that has and ID of my-header
, the close link in the panel should be:
<a href="#my-header" data-rel="close">Close panel</a>
Panel animations
Panels will animate if the browser supports 3D transforms. The presence of such support is established by the same criteria for CSS animation support we use for page transitions. Panel animations use translateX
CSS transforms to ensure they are hardware accelerated and smooth.
The framework has a feature test to detect if the required CSS properties are supported and will fall back to a simple hide/show if not available. After thorough testing, we decided to not animate panels on less capable platforms because the choppier animations weren't a better experience than a simple hide/show.
The animate
option allows you to turn off panel animations for all devices. To turn off animations via markup, add the data-animate="false"
attribute to the panel container.
The use of hardware acceleration is triggered during initialization of the page to prevent blinks when opening a panel. Because this increases memory use you have to be aware of performance issues if you use long lists or scripts to dynamically inject content on a page with an animated panel.
Panel positioning
The panel will be displayed with the position:absolute
CSS property, meaning it will scroll with the page. When a panel is opened the framework checks to see if the bottom of the panel contents is in view and, if not, scrolls to the top of the page.
You can set a panel to position:fixed
, so its contents will appear no matter how far down the page you're scrolled, by adding the data-position-fixed="true"
attribute to the panel. The framework also checks to see if the panel contents will fit within the viewport before applying the fixed positioning because this property would prevent the panel contents from scrolling and using overflow
is not well supported enough to use at this time. If the panel contents are too long to fit within the viewport, the framework will simply display the panel without fixed positioning.
In general, we recommend that you place the buttons that open the panel at the very top of the screen which is the most common UI pattern for panels. This will avoid the need to scroll and also makes the transitions a bit smoother.
Note that there are issues with fixed positioning within Android WebView applications (not the browser) that can cause layout issues, especially when hardware acceleration isn't enabled. We recommend not to use the fixed position panel option if deploying to an Android app. Also, if you have a fixed panel on a page with fixed toolbars, the toolbars might not transition together with the page content.
Styling panels
By default, panels have very simple styles to let you customize them as needed. Panels are essentially just simple blocks with no margins that sit on either side of the page content. The framework wraps the panel content in a div
with class ui-panel-inner
which has a padding of 15 pixels. If needed you can override this with custom CSS or use option classes.panelInner
to set a different class name for the div
.
Panels have a fixed width of 17em (272 pixels) which is narrow enough to still show some of the page contents when open to make clicking out to close easy, and still looks good on wider tablet or desktop screens. The styles to set widths on panels are fairly complex but these can be overridden with CSS as needed.
Note that adding padding, borders, or margins directly to the panel container will alter the overall dimensions and could cause the positioning and animation to be affected. To avoid this, apply styles to the panel content wrapper (.ui-panel-inner
).
Other than the theme background, width and 100% height styles, panels have very little styling on their own. The default theme for panels is "a". You can set a different theme for the panel by adding a data-theme
to the panel container, or set data-theme="none"
and add your own classes to style it as needed.
The framework applies the theme that is used for the page to the content wrapper. Before opening a panel that has display mode reveal or push, the page theme will be set to the same theme that is used for the panel. This is done to mask that most mobile browsers haven't finished painting the panel background when the animation to open it has already started. If you use a background image for a page, you have to set it for the ui-body-*
class of the theme that you use for the page so it will be used as background of the content wrapper.
Making the panel responsive
When the push or reveal display is used, a panel pushes the page aside when it opens. Since some of the page is pushed offscreen, the panel is modal and must be closed to interact with the page content again. On larger screens, you may want to have the panel work more like a collapsible column that can be opened and used alongside the page to take better use of the screen real estate.
To make the page work alongside the open panel, it needs to re-flow to a narrower width so it will fit next to the panel. This can be done purely with CSS by adding a left or right margin equal to the panel width (17em) to the page contents to force a re-flow. Second, the invisible layer placed over the page for the click out to dismiss behavior is hidden with CSS so you can click on the page and not close the menu.
Here is an example of these rules wrapped in a media query to only apply this behavior above 35em (560px):
@media (min-width:35em) { /* wrap on wide viewports once open */ .ui-panel-page-content-open.ui-panel-page-content-position-left { margin-right: 17em; } .ui-panel-page-content-open.ui-panel-page-content-position-right { margin-left: 17em; } .ui-panel-page-content-open { width: auto; } /* disable "dismiss" on wide viewports */ .ui-panel-dismiss { display: none; } /* same as the above but for panels with display mode "push" only */ .ui-panel-page-content-open.ui-panel-page-content-position-left.ui-panel-page-content-display-push { margin-right: 17em; } .ui-panel-page-content-open.ui-panel-page-content-position-right.ui-panel-page-content-display-push { margin-left: 17em; } .ui-panel-page-content-open.ui-panel-page-content-display-push { width: auto; } .ui-panel-dismiss-display-push { display: none; } }
Applying a preset breakpoint
Included in the widget styles is a breakpoint preset for this behavior that kicks in at 55em (880px). This breakpoint is not applied by default to make it easier for you to write custom breakpoints that work best for your content and design. To apply the breakpoint preset, add the ui-responsive-panel
class to the page (not the panel).
Options
animate
true
This option is also exposed as a data attribute:data-animate="false"
on the panel container.
Initialize the panel with the animate
option specified:
$( ".selector" ).panel({ animate: false });
Get or set the animate
option, after initialization:
// Getter var animate = $( ".selector" ).panel( "option", "animate" ); // Setter $( ".selector" ).panel( "option", "animate", false );
classes.animate
"ui-panel-animate"
true
.classes.contentFixedToolbar
"ui-panel-fixed-toolbar-wrap"
Class added to the page container to suppress scrolling horizontally
(version removed: 1.4)classes.contentFixedToolbarClosed
"ui-panel-content-fixed-toolbar-closed"
Class added to fixed toolbars after the close animation is complete.
(version removed: 1.4)classes.contentFixedToolbarOpen
"ui-panel-content-fixed-toolbar-open"
Class added to fixed toolbars when the panel is opening.
(version removed: 1.4)classes.contentWrap
"ui-panel-content-wrap"
Class added to the wrapper injected around the page contents (header, content, footer), needed for positioning of the panel.
(version removed: 1.4)classes.contentWrapClosed
"ui-panel-content-wrap-closed"
Class added to the page contents wrapper after the close animation is complete.
(version removed: 1.4)classes.contentWrapOpen
"ui-panel-content-wrap-open"
Class added to the wrapper injected around the page contents (header, content, footer) when the panel is opening. Used for targeting hardware acceleration only during transitions.
(version removed: 1.4)classes.modal
"ui-panel-dismiss"
classes.modalOpen
"ui-panel-dismiss-open"
classes.pageContainer
"ui-panel-page-container"
classes.pageContentPrefix
"ui-panel-page-content"
classes.pageFixedToolbar
"ui-panel-fixed-toolbar"
classes.pagePanel
"ui-page-panel"
Class added to the page container when a panel widget is present.
(version removed: 1.4)classes.pagePanelOpen
"ui-page-panel-open"
Class added to the page when a panel is open.
(version removed: 1.4)classes.panelFixed
"ui-panel-fixed"
classes.panelInner
"ui-panel-inner"
classes.panelOpen
"ui-panel-open"
defaults
false
true
indicates that other widgets options have default values and causes jQuery Mobile's widget autoenhancement code to omit the step where it retrieves option values from data attributes. This can improve startup time. This option is also exposed as a data attribute: data-defaults="true"
.
Initialize the panel with the defaults
option specified:
$( ".selector" ).panel({ defaults: true });
Get or set the defaults
option, after initialization:
// Getter var defaults = $( ".selector" ).panel( "option", "defaults" ); // Setter $( ".selector" ).panel( "option", "defaults", true );
disabled
false
true
. This option is also exposed as a data attribute: data-disabled="true"
.
Initialize the panel with the disabled
option specified:
$( ".selector" ).panel({ disabled: true });
Get or set the disabled
option, after initialization:
// Getter var disabled = $( ".selector" ).panel( "option", "disabled" ); // Setter $( ".selector" ).panel( "option", "disabled", true );
dismissible
true
This option is also exposed as a data attribute:data-dismissible="false"
on the link that opens the panel.
Initialize the panel with the dismissible
option specified:
$( ".selector" ).panel({ dismissible: false });
Get or set the dismissible
option, after initialization:
// Getter var dismissible = $( ".selector" ).panel( "option", "dismissible" ); // Setter $( ".selector" ).panel( "option", "dismissible", false );
display
"reveal"
"reveal" | Push the page over |
"push" | Re-flow the content to fit the panel content as a column |
"overlay" | Sit over the content |
This option is also exposed as a data attribute:data-display="push"
on the link that opens the panel.
Initialize the panel with the display
option specified:
$( ".selector" ).panel({ display: "overlay" });
Get or set the display
option, after initialization:
// Getter var display = $( ".selector" ).panel( "option", "display" ); // Setter $( ".selector" ).panel( "option", "display", "overlay" );
initSelector
See below
The default initSelector
for the panel widget is:
":jqmData(role='panel')"
Note: This option is deprecated in 1.4.0 and will be removed in 1.5.0.
As of jQuery Mobile 1.4.0, the initSelector
is no longer a widget option. Instead, it is declared directly on the widget prototype. Thus, you may specify a custom value by handling the mobileinit
event and overwriting the initSelector
on the prototype:
$( document ).on( "mobileinit", function() { $.mobile.panel.prototype.initSelector = "div.custom"; });
Note: Remember to attach the mobileinit
handler after you have loaded jQuery, but before you load jQuery Mobile, because the event is triggered as part of jQuery Mobile's loading process.
The value of this option is a jQuery selector string. The framework selects elements based on the value of this option and instantiates panel widgets on each of the resulting list of elements.
(version deprecated: 1.4.0)position
"left"
This option is also exposed as a data attribute:data-position="right"
on the link that opens the panel.
Initialize the panel with the position
option specified:
$( ".selector" ).panel({ position: "right" });
Get or set the position
option, after initialization:
// Getter var position = $( ".selector" ).panel( "option", "position" ); // Setter $( ".selector" ).panel( "option", "position", "right" );
positionFixed
false
This option is also exposed as a data attribute:data-position-fixed=true
on the panel.
Initialize the panel with the positionFixed
option specified:
$( ".selector" ).panel({ positionFixed: true });
Get or set the positionFixed
option, after initialization:
// Getter var positionFixed = $( ".selector" ).panel( "option", "positionFixed" ); // Setter $( ".selector" ).panel( "option", "positionFixed", true );
swipeClose
true
This option is also exposed as a data attribute:data-swipe-close=false
on the panel.
Initialize the panel with the swipeClose
option specified:
$( ".selector" ).panel({ swipeClose: false });
Get or set the swipeClose
option, after initialization:
// Getter var swipeClose = $( ".selector" ).panel( "option", "swipeClose" ); // Setter $( ".selector" ).panel( "option", "swipeClose", false );
theme
null, inherited from parent
Possible values: swatch letter (a-z).
This option is also exposed as a data attribute: data-theme="b"
.
Initialize the panel with the theme
option specified:
$( ".selector" ).panel({ theme: "b" });
Get or set the theme
option, after initialization:
// Getter var theme = $( ".selector" ).panel( "option", "theme" ); // Setter $( ".selector" ).panel( "option", "theme", "b" );
Methods
close()Returns: jQuery (plugin only)
- This method does not accept any arguments.
Invoke the close method:
$( ".selector" ).panel( "close" );
open()Returns: jQuery (plugin only)
- This method does not accept any arguments.
Invoke the open method:
$( ".selector" ).panel( "open" );
toggle()Returns: jQuery (plugin only)
- This method does not accept any arguments.
Invoke the toggle method:
$( ".selector" ).panel( "toggle" );
Events
beforeclose( event, ui )Type: panelbeforeclose
Note: The ui
object is empty but included for consistency with other events.
Initialize the panel with the beforeclose callback specified:
$( ".selector" ).panel({ beforeclose: function( event, ui ) {} });
Bind an event listener to the panelbeforeclose event:
$( ".selector" ).on( "panelbeforeclose", function( event, ui ) {} );
beforeopen( event, ui )Type: panelbeforeopen
Note: The ui
object is empty but included for consistency with other events.
Initialize the panel with the beforeopen callback specified:
$( ".selector" ).panel({ beforeopen: function( event, ui ) {} });
Bind an event listener to the panelbeforeopen event:
$( ".selector" ).on( "panelbeforeopen", function( event, ui ) {} );
close( event, ui )Type: panelclose
Note: The ui
object is empty but included for consistency with other events.
Initialize the panel with the close callback specified:
$( ".selector" ).panel({ close: function( event, ui ) {} });
Bind an event listener to the panelclose event:
$( ".selector" ).on( "panelclose", function( event, ui ) {} );
create( event, ui )Type: panelcreate
Note: The ui
object is empty but included for consistency with other events.
Initialize the panel with the create callback specified:
$( ".selector" ).panel({ create: function( event, ui ) {} });
Bind an event listener to the panelcreate event:
$( ".selector" ).on( "panelcreate", function( event, ui ) {} );
open( event, ui )Type: panelopen
Note: The ui
object is empty but included for consistency with other events.
Initialize the panel with the open callback specified:
$( ".selector" ).panel({ open: function( event, ui ) {} });
Bind an event listener to the panelopen event:
$( ".selector" ).on( "panelopen", function( event, ui ) {} );
Example:
A basic example of a panel.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>panel demo</title> <link rel="stylesheet" href="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="//code.jquery.com/jquery-1.10.2.min.js"></script> <script src="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> <style> .panel-content { padding: 1em; } </style> </head> <body> <div data-role="page" id="page1"> <div data-role="header"> <h1>jQuery Mobile Example</h1> </div> <div role="main" class="ui-content"> <a href="#defaultpanel" data-role="button" data-inline="true" data-icon="bars">Default panel</a> </div> <!-- defaultpanel --> <div data-role="panel" id="defaultpanel" data-theme="b"> <div class="panel-content"> <h3>Default panel options</h3> <p>This panel has all the default options: positioned on the left with the reveal display mode. The panel markup is <em>before</em> the header, content and footer in the source order.</p> <p>To close, click off the panel, swipe left or right, hit the Esc key, or use the button below:</p> <a href="#demo-links" data-rel="close" data-role="button" data-theme="a" data-icon="delete" data-inline="true">Close panel</a> </div><!-- /content wrapper for padding --> </div><!-- /defaultpanel --> </div> </body> </html>