Framework7 Cards and Panels — Content Containers, Expansion, and Side Panels
In this tutorial, you will learn about Framework7 Cards and Panels. We cover key concepts, practical examples, and best practices to help you master this topic.
Framework7 cards display content in visual containers with optional headers, footers, and expansion behavior, while panels provide side-drawer navigation with swipe gestures and overlay/cover modes.
What You'll Learn
- Creating cards with header and footer
- Expandable cards
- Left and right side panels
- Panel swipe gestures
- Panel events and modes
Why It Matters
Cards organize content into digestible visual blocks — product listings, articles, user profiles. Side panels provide navigation drawers commonly used in Material Design apps for menus, filters, and settings.
Real-World Use
An e-commerce app with product cards showing images, prices, and ratings (expandable for details), and a left panel for category navigation with swipe-to-open gesture.
Cards and Panels Architecture
flowchart TD
A[Page] --> B[Card]
A --> C[Panel]
B --> D[Card Header]
B --> E[Card Content]
B --> F[Card Footer]
C --> G[Left Panel]
C --> H[Right Panel]
G --> I[Menu Items]
H --> J[Settings/Info]
style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Basic Cards
<div class="page-content">
<div class="card">
<div class="card-header">User Profile</div>
<div class="card-content card-content-padding">
<div class="row">
<div class="col-30">
<img src="https://picsum.photos/100/100?random=1" width="80" style="border-radius:50%" />
</div>
<div class="col-70">
<h3>Alice Johnson</h3>
<p>Senior Developer at Acme Corp</p>
<p><i class="icon f7-icons">envelope</i> alice@example.com</p>
</div>
</div>
</div>
<div class="card-footer">
<a href="#" class="link">Message</a>
<a href="#" class="link">Call</a>
<a href="#" class="link">Email</a>
</div>
</div>
<div class="card">
<div class="card-header">Statistics</div>
<div class="card-content card-content-padding">
<div class="row">
<div class="col-33" style="text-align:center">
<h3>1,247</h3>
<small>Users</small>
</div>
<div class="col-33" style="text-align:center">
<h3>$84K</h3>
<small>Revenue</small>
</div>
<div class="col-33" style="text-align:center">
<h3>3.8K</h3>
<small>Orders</small>
</div>
</div>
</div>
</div>
</div>
Expected output: A profile card with avatar, info, and action buttons in the footer. A statistics card showing three metric columns.
Expandable Cards
<div class="card card-expandable">
<div class="card-content">
<div class="card-content-padding">
<img src="https://picsum.photos/800/400?random=1" width="100%" />
<h2>Beautiful Mountain View</h2>
<p>A stunning view of the mountain range at sunset.</p>
</div>
</div>
<div class="card-expandable-content">
<div class="card-content-padding">
<h3>Details</h3>
<p>This expansive mountain range spans over 300 miles across three states. The photo was taken at an elevation of 8,500 feet during the golden hour.</p>
<p>The area is known for its diverse wildlife including deer, eagles, and black bears. Hiking trails range from easy nature walks to challenging multi-day treks.</p>
<h3>Location</h3>
<p>Coordinates: 39.7392 N, 104.9903 W</p>
<p>Best visiting months: June through October</p>
<p><a href="#" class="button button-fill">Book a Tour</a></p>
</div>
</div>
</div>
// Card expand events
$$(document).on('card:expand', '.card-expandable', function(e) {
console.log('Card expanded');
});
$$(document).on('card:collapse', '.card-expandable', function(e) {
console.log('Card collapsed');
});
// Programmatic expand/collapse
app.card.expand('.card-expandable');
app.card.collapse('.card-expandable');
Expected output: Tapping the expandable card shows the full content in a full-screen overlay with a close button. The card:expand and card:collapse events fire during the transition.
Left and Right Panels
<!-- Panels are placed outside views, inside the app root -->
<div id="app">
<!-- Left panel -->
<div class="panel panel-left panel-cover">
<div class="page">
<div class="page-content">
<div class="block">
<div class="list">
<ul>
<li class="item-divider">Navigation</li>
<li>
<a href="#" class="item-link item-content panel-close">
<div class="item-media"><i class="icon f7-icons">house</i></div>
<div class="item-inner"><div class="item-title">Home</div></div>
</a>
</li>
<li>
<a href="/users/" class="item-link item-content panel-close">
<div class="item-media"><i class="icon f7-icons">person</i></div>
<div class="item-inner"><div class="item-title">Users</div></div>
</a>
</li>
<li>
<a href="/settings/" class="item-link item-content panel-close">
<div class="item-media"><i class="icon f7-icons">gear</i></div>
<div class="item-inner"><div class="item-title">Settings</div></div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Right panel -->
<div class="panel panel-right panel-reveal">
<div class="page">
<div class="page-content">
<div class="block">
<h3>Notifications</h3>
<div class="list">
<ul>
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title">New message from Bob</div>
<div class="item-after">2m ago</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title">Your order has shipped</div>
<div class="item-after">1h ago</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Your views -->
<div class="view view-main">
<!-- pages -->
</div>
</div>
Expected output: Swiping from the left edge opens the navigation panel (cover mode). Swiping from the right edge opens the notifications panel (reveal mode). Clicking panel-close links closes the panel.
Panel Modes and Gestures
<!-- Panel modes -->
<div class="panel panel-left panel-cover">Cover mode (overlays content)</div>
<div class="panel panel-left panel-reveal">Reveal mode (pushes content)</div>
<!-- Swipe-to-open panels -->
<div class="panel panel-left panel-cover" data-swipe="true">
<!-- Swipe from left edge to open -->
</div>
<div class="panel panel-right panel-reveal" data-swipe="true">
<!-- Swipe from right edge to open -->
</div>
// Open/close programmatically
app.panel.open('left');
app.panel.close('left');
app.panel.open('right');
app.panel.close();
// Toggle
app.panel.toggle('left');
// Panel events
$$(document).on('panel:open', function(e) {
var panel = e.detail.panel;
console.log('Panel opened:', panel.side);
});
$$(document).on('panel:close', function(e) {
var panel = e.detail.panel;
console.log('Panel closed:', panel.side);
});
$$(document).on('panel:swipe', function(e) {
var panel = e.detail.panel;
var progress = e.detail.progress;
console.log('Panel swipe progress:', progress);
});
// Check if panel is open
if (app.panel.isOpen('left')) {
console.log('Left panel is open');
}
// Enable/disable swipe
app.panel.enableSwipe('left');
app.panel.disableSwipe('left');
Expected output: Panels open with swipe gestures or programmatically. Cover mode overlays the content while reveal mode pushes it aside. Events track open, close, and swipe progress.
Panel with Navbar
<!-- Panel with its own navbar -->
<div class="panel panel-left panel-cover">
<div class="page">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Menu</div>
<div class="right">
<a href="#" class="link panel-close">
<i class="icon f7-icons">xmark</i>
</a>
</div>
</div>
</div>
<div class="page-content">
<div class="list">
<ul>
<li class="item-divider">Main</li>
<li>
<a href="/" class="item-link item-content panel-close">
<div class="item-media"><i class="icon f7-icons">house</i></div>
<div class="item-inner"><div class="item-title">Dashboard</div></div>
</a>
</li>
<li>
<a href="/analytics/" class="item-link item-content panel-close">
<div class="item-media"><i class="icon f7-icons">chart</i></div>
<div class="item-inner"><div class="item-title">Analytics</div></div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Trigger panel from navbar -->
<div class="navbar">
<div class="navbar-inner">
<div class="left">
<a href="#" class="link icon-only panel-open" data-panel="left">
<i class="icon f7-icons">bars</i>
</a>
</div>
<div class="title">Dashboard</div>
<div class="right">
<a href="#" class="link icon-only panel-open" data-panel="right">
<i class="icon f7-icons">bell</i>
</a>
</div>
</div>
</div>
Expected output: The navbar has hamburger and bell icons that open the left and right panels. The left panel has its own navbar with a close button.
Swipe Panel with List
<!-- Swipeable panel actions on list items -->
<div class="list media-list">
<ul>
<li>
<div class="swipeout">
<div class="swipeout-content item-content">
<div class="item-media"><img src="avatar1.jpg" width="44" /></div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">Alice</div>
<div class="item-after">2:45 PM</div>
</div>
<div class="item-text">Hey, are you coming to the meeting?</div>
</div>
</div>
<div class="swipeout-actions-right">
<a href="#" class="action1" style="background:#4caf50">Archive</a>
<a href="#" class="action2" style="background:#ff9800">Mute</a>
<a href="#" class="swipeout-delete" style="background:#f44343">Delete</a>
</div>
</div>
</li>
</ul>
</div>
Expected output: Swiping left on a list item reveals action buttons. This is different from panels but uses similar swipe gesture mechanics.
Common Mistakes
Placing panels inside views - Panels must be direct children of the app root (#app), not inside a view. Views are the main content area that panels overlay or push.
Not adding panel-close to navigation links - Links inside panels should have the panel-close class to close the panel after navigation, unless you want the panel to stay open.
Forgetting data-swipe attribute - Panels do not have swipe gestures enabled by default. Add data-swipe="true" to enable swipe-to-open.
Using too much content in cover panels - Cover panels overlay the view. If the panel content is taller than the screen, it scrolls independently, which can confuse users.
Not handling both left and right panels - Opening one panel does not automatically close the other. Check if one is open before opening the other, or close both before opening.
Practice Questions
- What is the difference between cover and reveal panel modes?
- How do you enable swipe-to-open for a panel?
- How do you open a panel programmatically?
- What is an expandable card and how does it work?
- How do you close a panel after clicking a navigation link inside it?
Challenge: Build a mobile app with: a left panel (navigation menu with Dashboard, Users, Settings links, each with icons), a right panel (notifications list with timestamps), swipe gesture enabled on both panels, a hamburger icon in the navbar to open the left panel, a bell icon to open the right panel, and expandable cards in the main content area showing product details.
FAQ
Mini Project
Build a news reader app with: a left panel for categories (Technology, Sports, Business, Science), a right panel for bookmarked articles, swipe-to-open on both panels, expandable article cards showing title, image, summary, and full content on expand, navbar with hamburger and bookmark icons, and smooth panel transitions.
What's Next
Cards and panels organize content. Learn how Framework7 Modals and Popups create dialogs, action sheets, popovers, and toast notifications.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro