Framework7 Modals and Popups — Dialogs, Action Sheets, Toasts, and Popovers
In this tutorial, you will learn about Framework7 Modals and Popups. We cover key concepts, practical examples, and best practices to help you master this topic.
Framework7 modals and popups provide mobile-optimized dialogs — alerts, confirms, prompts, action sheets, popovers, toasts, progress indicators, login screens, and custom popup Windows.
What You'll Learn
- Dialog alerts, confirms, and prompts
- Action sheets with cancel and destructive buttons
- Popovers for iPad-style context menus
- Toast notifications
- Progress and preloader dialogs
- Custom popup windows
Why It Matters
Mobile apps need touch-friendly dialogs that respect platform conventions — iOS-style action sheets at the bottom, Material-style dialogs centered. Framework7 provides all modal types with platform-appropriate styling.
Real-World Use
A document editor app with a confirmation dialog before deleting, an action sheet for sharing options, a toast for save confirmation, a popover for formatting options, and a login popup for authentication.
Modals Architecture
flowchart TD
A[Modals] --> B[Dialogs]
A --> C[Action Sheet]
A --> D[Popover]
A --> E[Toast]
A --> F[Popup]
B --> G[Alert]
B --> H[Confirm]
B --> I[Prompt]
B --> J[Login]
E --> K[Success]
E --> L[Error]
E --> M[Info]
style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Dialog Alerts, Confirms, and Prompts
// Alert
app.dialog.alert('Your message has been sent successfully.', function() {
console.log('Alert dismissed');
});
// Alert with title
app.dialog.alert('Connection lost. Please check your network.', 'Network Error');
// Confirm
app.dialog.confirm('Are you sure you want to delete this item?', function() {
console.log('Confirmed - delete item');
}, function() {
console.log('Cancelled');
});
// Confirm with custom title
app.dialog.confirm(
'Unsaved changes will be lost. Continue?',
'Confirm Navigation',
function() { console.log('Leave page'); },
function() { console.log('Stay'); }
);
// Prompt
app.dialog.prompt('Enter your name:', function(value) {
console.log('Name entered:', value);
}, function() {
console.log('Prompt cancelled');
}, 'Default Name', 'Please enter your name');
// Custom dialog
app.dialog.create({
title: 'Custom Dialog',
text: 'This is a custom dialog with buttons.',
buttons: [
{
text: 'Button 1',
bold: true,
onClick: function() { console.log('Button 1'); }
},
{
text: 'Button 2',
onClick: function() { console.log('Button 2'); }
},
{
text: 'Cancel',
close: true
}
],
verticalButtons: true
}).open();
Expected output: Alert shows with an OK button. Confirm shows OK and Cancel buttons. Prompt shows a text input field. Custom dialog shows three vertically arranged buttons.
Action Sheet
// Action sheet
app.dialog.actions('Share via:', [
[
{
text: '<i class="icon f7-icons">envelope</i> Email',
onClick: function() { console.log('Share via Email'); }
},
{
text: '<i class="icon f7-icons">message</i> Message',
onClick: function() { console.log('Share via Message'); }
},
{
text: '<i class="icon f7-icons">link</i> Copy Link',
onClick: function() { console.log('Link copied'); }
}
],
[
{
text: 'Cancel',
close: true,
color: 'red'
}
]
]);
// Action sheet with destructive button
app.dialog.actions('Photo Options', [
[
{
text: 'Take Photo',
onClick: function() { console.log('Camera'); }
},
{
text: 'Choose from Library',
onClick: function() { console.log('Gallery'); }
}
],
[
{
text: 'Delete Photo',
color: 'red',
onClick: function() { console.log('Delete'); }
}
],
[
{
text: 'Cancel',
close: true
}
]
]);
// Action sheet as grid
app.dialog.actions('Quick Actions', [
[
{
text: 'Edit',
icon: '<i class="icon f7-icons">pencil</i>'
},
{
text: 'Copy',
icon: '<i class="icon f7-icons">doc-on-doc</i>'
},
{
text: 'Share',
icon: '<i class="icon f7-icons">square-and-arrow-up</i>'
}
]
], { grid: true });
Expected output: Action sheet slides up from the bottom with option groups separated by dividers. A cancel button is at the bottom. Grid layout shows icons above text in a grid.
Popover
<!-- Trigger element -->
<button class="button popover-open" data-popover=".my-popover">Open Popover</button>
<!-- Popover content -->
<div class="popover my-popover">
<div class="popover-inner">
<div class="list">
<ul>
<li>
<a href="#" class="item-link item-content popover-close">
<div class="item-media"><i class="icon f7-icons">pencil</i></div>
<div class="item-inner"><div class="item-title">Edit</div></div>
</a>
</li>
<li>
<a href="#" class="item-link item-content popover-close">
<div class="item-media"><i class="icon f7-icons">duplicate</i></div>
<div class="item-inner"><div class="item-title">Duplicate</div></div>
</a>
</li>
<li>
<a href="#" class="item-link item-content popover-close">
<div class="item-media"><i class="icon f7-icons">trash</i></div>
<div class="item-inner"><div class="item-title">Delete</div></div>
</a>
</li>
</ul>
</div>
</div>
</div>
// Programmatic popover
app.popover.create({
el: '.my-popover',
targetEl: '.popover-open',
on: {
open: function(popover) { console.log('Popover opened'); },
close: function(popover) { console.log('Popover closed'); }
}
}).open();
// Popover events
$$(document).on('popover:open', '.popover', function(e) {
console.log('Popover opened');
});
Expected output: Clicking the button opens a popover anchored to the button. On iPad, it appears as a popover bubble. On iPhone, it falls back to an action sheet.
Toast Notifications
// Simple toast
app.toast.create({
text: 'Message sent!',
position: 'center', // 'center', 'top', 'bottom'
closeTimeout: 2000,
closeButton: false
}).open();
// Toast with close button
app.toast.create({
text: 'Item saved to favorites',
position: 'bottom',
closeButton: true,
closeButtonText: 'Undo',
closeButtonColor: 'blue',
on: {
close: function(toast) {
console.log('Toast closed');
}
}
}).open();
// Toast with icon
app.toast.create({
text: 'Sync complete',
icon: '<i class="icon f7-icons">checkmark-circle</i>',
position: 'top',
closeTimeout: 3000
}).open();
// Error toast
app.toast.create({
text: 'Connection failed',
position: 'bottom',
closeTimeout: 4000,
destroyOnClose: true,
cssClass: 'toast-error'
}).open();
// Progress toast
var progressToast = app.toast.create({
text: 'Uploading... 0%',
position: 'center',
closeTimeout: 0 // Manual close
});
progressToast.open();
// Update progress
var progress = 0;
var interval = setInterval(function() {
progress += 10;
progressToast.setText('Uploading... ' + progress + '%');
if (progress >= 100) {
clearInterval(interval);
progressToast.close();
}
}, 500);
Expected output: Toast appears at the specified position, auto-dismisses after the timeout, or shows a close button. Progress toast updates text in real time.
Progress and Preloader
// Preloader (spinner)
app.dialog.preloader('Loading...');
setTimeout(function() {
app.dialog.close();
}, 2000);
// Progress dialog
app.dialog.progress('Upload progress', 0);
// Update progress
var progress = 0;
var interval = setInterval(function() {
progress += 0.1;
app.dialog.setProgress(progress);
if (progress >= 1) {
clearInterval(interval);
app.dialog.close();
app.dialog.alert('Upload complete!');
}
}, 300);
// Inline preloader
<div class="preloader"></div>
<div class="preloader preloader-white"></div>
<div class="preloader" data-size="44"></div>
// Preloader with text
<span class="preloader"></span>
<span>Loading...</span>
// Color preloader
<div class="preloader" style="--f7-preloader-color: #4a90d9"></div>
Expected output: A spinner preloader shows while loading. Progress dialog shows a progress bar that fills over time. Inline preloaders can be placed inside buttons or text.
Login Modal
// Login modal
app.dialog.login('Sign In', function(username, password) {
console.log('Login:', username, password);
// Authenticate
if (username === 'admin' && password === 'password') {
app.dialog.close();
app.dialog.alert('Welcome, ' + username + '!');
} else {
app.dialog.alert('Invalid credentials');
}
}, function() {
console.log('Login cancelled');
});
// Custom login popup
app.popup.create({
el: '#login-popup',
on: {
open: function(popup) {
console.log('Login popup opened');
}
}
}).open();
<!-- Login popup HTML -->
<div class="popup" id="login-popup">
<div class="page">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Sign In</div>
<div class="right">
<a href="#" class="link popup-close">Cancel</a>
</div>
</div>
</div>
<div class="page-content">
<div class="block">
<div class="list" style="margin:0">
<ul>
<li>
<div class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Username</div>
<div class="item-input-wrap">
<input type="text" id="login-username" placeholder="Username" />
</div>
</div>
</div>
</li>
<li>
<div class="item-content item-input">
<div class="item-inner">
<div class="item-title item-label">Password</div>
<div class="item-input-wrap">
<input type="password" id="login-password" placeholder="Password" />
</div>
</div>
</div>
</li>
</ul>
</div>
<button class="button button-fill button-large" id="login-btn">Sign In</button>
</div>
</div>
</div>
</div>
Expected output: The login modal shows username and password fields with platform styling. On submit, it authenticates and shows a welcome alert or error.
Custom Popup
<!-- Popup trigger -->
<button class="button popup-open" data-popup="#my-popup">Open Popup</button>
<!-- Popup content -->
<div class="popup" id="my-popup">
<div class="page">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Settings</div>
<div class="right">
<a href="#" class="link popup-close">Done</a>
</div>
</div>
</div>
<div class="page-content">
<div class="list">
<ul>
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title">Notifications</div>
<div class="item-after">
<label class="toggle"><input type="checkbox" /><span class="toggle-icon"></span></label>
</div>
</div>
</div>
</li>
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title">Dark Mode</div>
<div class="item-after">
<label class="toggle"><input type="checkbox" /><span class="toggle-icon"></span></label>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
// Popup events
$$(document).on('popup:open', '#my-popup', function(e) {
console.log('Popup opened');
});
$$(document).on('popup:close', '#my-popup', function(e) {
console.log('Popup closed');
});
// Programmatic
app.popup.create({
el: '#my-popup',
closeByOutside: true,
animate: true
}).open();
Expected output: The popup opens as a full-screen page with its own navbar. It stacks above the current view and can contain any Framework7 content.
Common Mistakes
Not handling dialog callback timing - Dialog callbacks fire after the user taps a button. For async operations, start the operation inside the callback, not before.
Using too many toasts simultaneously - Multiple toasts stack vertically. Limit concurrent toasts to 2-3 to avoid visual clutter. Use a queue system for sequential toasts.
Forgetting to close preloader on error - If an operation fails, the preloader stays visible forever. Always close the preloader in both success and error callbacks.
Creating popups without destroyOnClose - Popup instances persist in memory after close. Set destroyOnClose: true or call popup.destroy() in the close callback.
Placing complex forms inside action sheets - Action sheets are for simple button lists. Use popups for complex forms, and action sheets for choice selection only.
Practice Questions
- How do you show a confirmation dialog with two callbacks?
- What is the difference between an action sheet and a popover?
- How do you create a toast with a close button and a custom action?
- How do you update a progress dialog programmatically?
- How do you create a custom popup with a form?
Challenge: Build a photo sharing app flow: a long-press on a photo shows an action sheet (Share, Edit, Delete with destructive color), Delete shows a confirm dialog, Share opens a popover with sharing options, a toast confirms the action, and a progress dialog shows during upload.
FAQ
Mini Project
Build a file management app with: a long-press action sheet on files (Rename, Move, Delete, Share), confirm dialog before delete, toast notification for successful operations, progress dialog during file upload, popover for file info/details, and a custom popup for move-to-folder selection with a list view.
What's Next
Modals handle user interactions. Learn how Framework7 Side Panels create navigation drawers with advanced swipe gestures and nested content.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro