Framework 7 is a free and open source mobile HTML framework to develop hybrid mobile apps or web apps with iOS and Android native look and feel. It is also an indispensable prototyping application tool to show a working app prototype as soon as possible in case you need to.
In this tutorial, we’ll demonstrate how to get started with Framework7 in building full-featured iOS and Android applications
Installation
There are a few ways to get started with Framework7.
- Download/install from Github: we can download required Framework7 files from Framework7 GitHub repository.
- Use any of the starter app templates: Framework7 has already built starter templates like the official Framework7 starter templates, Offical Adobe PhoneGap templates, and the community starter apps templates.
- Install From NPM: we can also install Framework7 from NPM:$ npm install framework7
From the downloaded core package, we will need files from the CSS
and JS
folders
This feature currently can be used in bundlers like Webpack and Rollup
Having npm installed Framework7, it can be imported as an ES-next module:
import Framework7 from 'framework7';
Framework7 has a modular structure, and by default, it exports only Framework7 with core components. Therefore, if you need additional components they must be included separately:
// Import core framework
import Framework7 from 'framework7';
// Import additional components
import Searchbar from 'framework7/components/searchbar/searchbar.js';
// Install F7 Components using .use() method on class:
Framework7.use([Searchbar]);
// Init app
var app = new Framework({/*...*/});
Such modular structure provides best widget tree structure and packages size optimization. In addition to default
export, it has named export for Template7
, Dom7
, Request
, Device
, Utils
and Support
libraries:
import Framework7, { Device, Request } from 'framework7';
var app = new Framework({/*...*/});
if (Device.ios) {
Request.get('http://google.com');
}
Layouts
Now when you have downloaded/installed Framework7, you can start by creating a layout. The Framework7 layout structure is very important given that it targets native mobile devices. Here’s a typical Framework7 HTML layout page:
<!DOCTYPE html>
<html>
<head>
<!-- Required meta tags-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- Color theme for statusbar -->
<meta name="theme-color" content="#2196f3">
<!-- Your app title -->
<title>My App</title>
<!-- Path to Framework7 Library CSS -->
<link rel="stylesheet" href="path/to/framework7.min.css">
<!-- Path to your custom app styles-->
<link rel="stylesheet" href="path/to/my-app.css">
</head>
<body>
<!-- App root element -->
<div id="app">
<!-- Statusbar overlay -->
<div class="statusbar"></div>
<!-- Your main view, should have "view-main" class -->
<div class="view view-main">
<!-- Initial Page, "data-name" contains page name -->
<div data-name="home" class="page">
<!-- Top Navbar -->
<div class="navbar">
<div class="navbar-inner">
<div class="title">Awesome App</div>
</div>
</div>
<!-- Toolbar -->
<div class="toolbar">
<div class="toolbar-inner">
<!-- Toolbar links -->
<a href="#" class="link">Link 1</a>
<a href="#" class="link">Link 2</a>
</div>
</div>
<!-- Scrollable page content -->
<div class="page-content">
<p>Page content goes here</p>
<!-- Link to another page -->
<a href="/about/">About app</a>
</div>
</div>
</div>
</div>
<!-- Path to Framework7 Library JS-->
<script type="text/javascript" src="path/to/framework7.min.js"></script>
<!-- Path to your app js-->
<script type="text/javascript" src="path/to/my-app.js"></script>
</body>
</html>
This looks a lot like every other HTML file however it is important that you maintain the structure to get the best out of your Framework7 applications. If you used any of the provided official templates, it comes with fully featured HTML files to get you started easily.
Initialization
Now when you have the basic template, you’ll need to initialize the app in the JavaScript file. With the links to the CSS and JS files added in the appropriate places inside the layout file, you can go ahead and initialize the app in the linked JavaScript file. For example, we linked my-app.js
in the layout file. Inside the my-app.js
file we initialize the app like so:
var app = new Framework7();
In the example above we use the app
variable where we store Framework7 initialized instance for easy access in the future. It is not necessary to name it app
, it could be any name you like.
It is pretty simple. However, Framework7 also provides more customization on initialization by passing an object with parameters:
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
// Enable swipe panel
panel: {
swipe: 'left',
},
// Add default routes
routes: [
{
path: '/about/',
url: 'about.html',
},
],
// ... other parameters
});
For a list of all available app parameters, check the app/core section on the Framework 7 docs page.
After you initialized the app, you need to initialize the View (<div class="view view-main">
in the app layout). The View is basically the app router which is responsible for navigation:
var mainView = app.views.create('.view-main');
So your final initialization code in my-app.js
could look like:
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
// Enable swipe panel
panel: {
swipe: 'left',
},
// Add default routes
routes: [
{
path: '/about/',
url: 'about.html',
},
],
// ... other parameters
});
var mainView = app.views.create('.view-main');
Ok, now we know how to scaffold and initialize the app, let’s talk about events.
Events
Most of the Framework7 components that are built with classes/constructors (including the Framework7 class itself) all have some kind of event emitter API. It allows us to easily emit and handle all kind of events, including events between components.
Event handlers in parameters
When you create an app instance or any other component using API, you can pass event handlers on app/component initialization in **on**
parameter:
var app = new Framework7({
...
on: {
// each object key means same name event handler
pageInit: function (page) {
// do something on page init
},
popupOpen: function (popup) {
// do something on popup open
},
},
});
Event instance methods
In Framework7, It is possible to add/remove event handlers using the following instance methods:
[instance].on(event, handler) | Add event handler |
---|---|
[instance].once(event, handler) | Add an event handler that will be removed after it was fired |
[instance].off(event) | Remove all handlers for the specified event |
[instance].emit(event, …args) | Fire event on the instance |
Adding event handlers
Here is how you add event handlers in Framework7:
var app = new Framework7({/*...*/});
var popup = app.popup.create({/*...*/});
app.on('pageInit', function (page) {
// do something on page init
});
popup.on('open', function (popup) {
// do something on popup open
});
// The `once` handler will only work once
popup.once('close', function (popup) {
// do something on popup close
});
This looks a bit lengthy but there’s a way around it. Framework7 allows you to add multiple event handlers at once. We can pass multiple events as the first parameter, separated by spaces:
app.on('popupOpen popupClose', function (popup) {
// do something on popupOpen and popupClose
});
Remove event handlers
In Framework7, named function handlers can be removed:
function onTabShow() {
// do something on tab show
}
// add handler
app.on('tabShow', onTabShow);
// later remove tabShow handler:
app.off('tabShow', onTabShow);
Remove all handlers
If we don’t pass a second handler argument to the .off
method then we can remove all handlers assigned for this event:
// Remove all tabShow handlers
app.off('tabShow');
Emit events
And of course we can emit events and any kind of custom events we may need:
app.on('myCustomEvent', function (a, b) {
console.log(a); // -> 'foo'
console.log(b); // -> 'bar'
});
app.emit('myCustomEvent', 'foo', 'bar');
Event handler context
Event handler context (this
) always points to the instance where it was assigned:
app.on('popupOpen', function () {
console.log(this); // -> app instance
});
popup.on('popupOpen', function () {
console.log(this); // -> popup instance
});
Router/Navigation
Routes
When you initialize the Framework7 app, you should pass default routes using the routes
array parameter:
var app = new Framework7({
routes: [
{
name: 'about',
path: '/about/',
url: './pages/about.html',
},
Routes defined on app initialization are default routes, they will be available for any View/Router in the app.
If however you have a Multi-View/Router app and you want to some View/Router to have its own strict routes and don’t want default routes to be available in the View, then you may specify the same routes
parameter on View init:
var view1 = app.views.create('.view-1', {
routes: [
{
path: '/users/',
url: './pages/users.html',
},
{
path: '/user/',
url: './pages/user.html',
},
],
});
Route properties
Let’s now see what each route property means:
Parameter | Type | Description |
---|---|---|
name | string | Route name, e.g. home |
path | string | Route path. Means this route will be loaded when we click the link that matches to this path or can be loaded by this path using API |
options | object | Object with additional route options (optional) |
routes | array | Array with nested routes |
Content related properties
The following route properties define how (from where/what) content should be loaded:
el | HTMLElement | Load page from DOM bypassed HTMLElement |
---|---|---|
pageName | string | Load page from DOM that has same data-name attribute |
content | string | Creates a dynamic page from a specified content string |
url | string | Load page content via Ajax. |
Also supports dynamic route params from route path using {{paramName}}
expression, |
Route path
As stated above, the route’s path
property means the path/url that will be displayed in the browser window address bar (if pushState
enabled) when the following route will be loaded either by API or clicking on a link with the same path.
Route path matching is handled by a library called Path To Regex, so everything that is supported there is supported in Framework7 as well. For example, if you want to add a default route that matches all paths, use a regular expression like:
// Default route, match to all pages (e.g. 404 page)
{
path: '(.*)',
url: './pages/404.html',
},
Router component
Router component is a special type of content that can be loaded by Router when we specify route content using component
or componentUrl
properties.
It should help to better structure our apps, keep things in appropriate places, and make many things quicker and in a more clear and comfortable way.
Router API methods and properties
View’s main purpose is navigating/routing between pages. We can access its router instance by view.router
. It has a lot of useful methods and properties to take control over routing and navigation, here’s a few:
Router Properties | |
---|---|
router.app | Link to global app instance |
router.view | Link to related View instance |
router.params | Object with router initialization parameters |
router.el | Router’s view HTML element |
Router methods
Router Methods | |
---|---|
router.navigate(url, options) | Navigate to (load) new page |
– url string – url to navigate to | |
– options | |
router.back(url, options) | Go back to the previous page, going back in the View history |
– url string – url to navigate to (optional). | |
– options | |
router.refreshPage() | Refresh/reload the current page |
router.clearPreviousHistory() | Clear router previous pages history and remove all previous pages from DOM |
router.on(event, handler) | Add event handler |
router.once(event, handler) | Add an event handler that will be removed after it was fired |
router.off(event, handler) | Remove event handler |
router.off(event) | Remove all handlers for the specified event |
router.emit(event, …args) | Fire event on the instance |
Linking between pages and views
It may be not very comfortable to use router methods all the time to navigate between pages. In many cases, we can just use links to navigate between pages. And we can pass additional navigation parameters using data-
attributes:
<a href="/somepage/">Some Page</a>
<a href="/somepage/" data-animate="false" data-reload-current="true">Some Page</a>
<a href="#" class="back">Go back</a>
<a href="/home/" data-force="true" data-ignore-cache="true" class="back">Go back</a>
Links default behavior:
- If a link is in the inside of a not-initialized view, then it will load the page in the main view
- If a link is in inside of an initialized view, then it will load a page in this view (if other view is not specified in view’s
linksView
parameter)
But if we need to load the page in another view we can specify this view’s CSS selector in link’s data-view
attribute
<div class="view view-init view-left" data-name="left">
...
<a href="/some-page/" data-view=".view-main">Some Page</a>
...
</div>
<div class="view view-init view-main">
...
<a href="/another-page/" data-view=".view-left">Another Page</a>
...
</div>
Component structure
If you know about Vue components, then it will be much easier to understand this one as it looks pretty similar. Router Component is basically an object with the following properties (all properties are optional and not all are listed here):
Property | Type | Description |
---|---|---|
template | string | Template7 template string. Will be compiled as a Template7 template |
render | function | Render function to render the component. Must return full HTML string or HTMLElement |
data | function | Component data, the function must return component context data |
You can read more about the properties here.
Component context
All component methods and the Template7 compiler are executed in the context of the component.
Component context is the object you have returned in the component’s data
and methods from specified methods
object.
Component page events
Component page event handlers can be passed in the on
component property. They are usually DOM Page Events
. Because they are DOM events, they accept event
as the first argument, and Page Data
as the second argument. The only difference between them and the usual DOM events is that their context (this
) is bound to the component context and event handler name must be specified in camelCase format.
Styles
iPhone X Styles
With the iPhone X release, Apple introduced so-called “safe areas”, when the app UI must include additional top/bottom spacing (to consider top notch and new bottom bar) in portrait orientation and additional left/right spacing (to consider left/right notch) in landscape orientation.
In portrait orientation, Framework7 will do the required style modifications automatically, but in landscape orientation, some additional classes must be added to elements:
ios-edges |
Add to the element that is stick to left/right screen edges in landscape orientation. |
---|---|
ios-left-edge |
Add to the element that is stick to the left screen edge in landscape orientation. |
ios-right-edge |
Add to the element that is stick to the right screen edge in landscape orientation. |
no-ios-edges |
Add to the element which is inside of ios-edges to remove additional horizontal spacing. |
no-ios-left-edge |
Add to the element which is inside of ios-edges to remove additional left spacing. |
no-ios-right-edge |
Add to the element which is inside of ios-edges to remove additional right spacing. |
The following elements don’t require such classes:
- Popup, Sheet – already considered as full-screen elements that require extra spacing on both left and right sides
- Left Panel – already considered an element that is stick to the left screen edge and requires extra spacing on left side
- Right Panel – already considered as an element that is stick to the right screen edge and requires extra spacing on the right side
Here is the example app layout with such classes:
<body>
<!-- app root -->
<div id="app">
<!-- statusbar -->
<div class="statusbar"></div>
<!-- left panel doesn't require any additional classes -->
<div class="panel panel-left panel-cover">
...
</div>
<!-- right panel doesn't require any additional classes -->
<div class="panel panel-right panel-reveal">
...
</div>
<!-- main view, full-wide element, add "ios-edges" class -->
<div class="view view-main view-init ios-edges" data-url="/">
<div class="page">
<div class="navbar">
...
</div>
<div class="page-content">
<!-- full-wide list, will inherit ios-edges from view -->
<div class="list">
...
</div>
<!-- full-wide content block, will inherit ios-edges from view -->
<div class="block">
...
</div>
<!--
two-columns blocks: need to
- remove extra spacing on right side for left block
- remove extra spacing on left side for right block
-->
<div class="row">
<!-- remove right spacing on left block -->
<div class="block col no-ios-right-edge">
...
</div>
<!-- remove left spacing on right block -->
<div class="block col no-ios-left-edge">
...
</div>
</div>
...
</div>
</div>
</div>
</div>
<script src="../packages/core/js/framework7.min.js"></script>
<script src="js/routes.js"></script>
<script src="js/app.js"></script>
</body>
Color themes
Framework7 comes with nine ready to use default color themes. Note that colors vary a bit for iOS and MD themes to match official guidelines.
Color | iOS | MD |
---|---|---|
red | #ff3b30 | #f44336 |
green | #4cd964 | #4caf50 |
blue | #007aff | #2196f3 |
pink | #e91e63 | #e91e63 |
yellow | #ffcc00 | #ffeb3b |
orange | #ff9500 | #ff9800 |
gray | #8e8e93 | #9e9e9e |
white | #fff | #fff |
black | #000 | #000 |
Apply color themes
It is easy to apply color themes. All you need is just to add the color-theme-[color]
class to the required parent element. It could be body, app root, view, page, navbar, toolbar, list-block, etc. For example:
<body class="color-theme-red">
...
</body>
<div class="page color-theme-green">
...
</div>
<div class="list-block color-theme-pink">
...
</div>
<div class="navbar color-theme-orange">
...
</div>
<div class="segmented color-theme-yellow">
...
</div>
The applied color theme affects only interactive elements such as links, buttons, form elements, icons. It doesn’t change basic text color or background colors on other blocks.
Layout themes
Framework7 also has an additional dark theme layout. To apply a dark theme we need to add the theme-dark
class to the required parent element. It could be body, app root, view, page, navbar, toolbar, list-block, etc. For example:
<body class="theme-dark">
...
</body>
<div class="page theme-dark">
...
</div>
<div class="list-block theme-dark">
...
</div>
Helper classes
There are also additional helper classes that could be used without/outside color themes:
color-[color]
– if you want to change the color of the individual button, link or icon, for example:
<a class="button color-red">Red button</a>
text-color-[color]
– if you want to change the text color of the required element:
<p class="text-color-red">Red color text</p>
bg-color-[color]
– if you want to quickly set the predefined background color on some block or element:
<span class="badge bg-color-pink">14</span>
– pink badge
border-color-[color]
– if you want to set predefined border color:
<div class="button border-color-red">...</div>
And of course, you can mix these helper classes:
<div class="navbar bg-color-blue text-color-white border-color-gray">...</div>
DOM7
Framework7 doesn’t use any third party libraries, even for DOM manipulation. It has its own custom DOM library – DOM7 – that utilizes cutting edge and high-performance methods for DOM manipulation. You don’t need to learn something new, its usage is very simple because it has the same syntax as the well known jQuery library with support of the most popular and widely used methods and jQuery-like chaining.
To start using it, there is a Dom7
global window function, but it is recommended to assign it to some local variable with a more handy name, like $$
, but not to $
to prevent conflicts with other libraries like jQuery or Zepto:
//Export DOM7 to local variable to make it easily accessible
var $$ = Dom7;
### Usage example
Just everything you already know:
``` language-javascript
$$('.something').on('click', function (e) {
$$(this).addClass('hello').attr('title', 'world').insertAfter('.something-else');
});
Available methods
All these methods work almost in the same way and with the same arguments as in jQuery or Zepto:
$$(window).trigger('resize');
This also applies to it’s associating classes, attributes, properties, data storage, DOM manipulation etc.
Template7
Template7 is a mobile-first JavaScript template engine with Handlebars-like syntax.
It is ultra lightweight (around 1KB minified and gzipped) and blazing fast (up to three times faster than Handlebars in mobile Safari!) and it is already included in Framework7. So you don’t need to include any additional scripts.
Usage and API
Сheck out the Template7 website for the most relevant guide and API. But skip the part about downloading, it is already included into Framework7.
Performance tips
Template7 is fast and you can make it work even faster in your apps. The slowest part (but still very fast in T7) in all this compilation/rendering process is the compilation from string to pure JS function when you do Template7.compile()
. So don’t compile the same templates multiple times, one time will be enough:
// Initialize app
var app = new Framework7();
var $$ = Dom7;
// Compile templates once on app load/init
var searchTemplate = $$('script#search-template').html();
var compiledSearchTemplate = Template7.compile(searchTemplate);
var listTemplate = $$('script#list-template').html();
var compiledListTemplate = Template7.compile(listTemplate);
// That is all, now and further just execute compiled templates with required context
app.on('pageInit', function (page) {
// Just execute compiled search template with required content:
var html = compiledSearchTemplate({/*...some data...*/});
// Do something with html...
});
Template7 can also be used as a standalone library without Framework7. You will need to download it at Template7 GitHub repo
Utilities
Ajax Request
Framework7 comes with handy Request library to work with XHR requests (Ajax) right from the box. It is available as a request
property of the Framework7 class Framework7.request
and the same property on the initialized app instance (app.request
):
// If you need it in a place where you don't have access to app instance or before you init the app, do:
Framework7.request.get('somepage.html', function (data) {
console.log(data);
});
// After you init the app, you can access it as app instance property:
var app = new Framework7({ /*...*/ });
app.request.get('somepage.html', function (data) {
console.log(data);
});
To load data from the server use:
app.request(parameters)
where:
parameters = object – Request parameters.
Returns plain XHR object.
In Framework7, To load data from the server use:
Framework7.request(parameters)
where:
parameters = object – Request parameters.
Returns plain XHR object.
The API also supports a long list of parameters and callbacks that makes it seamless to use.
Shorthand methods
The framework7 request comes with some pre-configured methods for ease of use.
Get
To load data from the server using an HTTP GET request, use:Framework7.request.get(url, data, success, error, dataType)
.
The request returns a plain XHR object.
For example:
var app = new Framework7();
var $$ = Dom7;
app.request.get('blog-post.php', { foo:'bar', id:5 }, function (data) {
$$('.articles').html(data);
console.log('Load was performed');
});
Post
To load data from the server using an HTTP POST request use: F``ramework7.request.post(url, data, success, error, dataType)
.
The request returns a plain XHR object.
For example:
var app = new Framework7();
var $$ = Dom7;
app.request.post('auth.php', { username:'foo', password: 'bar' }, function (data) {
$$('.login').html(data);
console.log('Load was performed');
});
JSON
To load data from the server in JSON format, use: Framework7.request.json(url, data, success, error)
.
The method returns a JSON object.
For example:
Framework7.request.json('items.json', function (data) {
console.log(data);
});
var app = new Framework7();
app.request.json('users.json', function (data) {
console.log(data);
});
PostJSON
To send JSON data using a HTTP POST request, use: Framework7.request.postJSON(url, data, success, error, dataType)
.
The request returns a plain XHR object
For example:
var app = new Framework7();
var $$ = Dom7;
app.request.postJSON('http://api.myapp.com', { username:'foo', password: 'bar' }, function (data) {
console.log(data);
});
Request setup
Framework7.request.setup(parameters)
– set default values for future Ajax requests.
For example:
// After the following setup all XHR requests will have an additional 'Autorization' header
Framework7.request.setup({
headers: {
'Authorization': 'sometokenvalue'
}
})
Original request parameters
Each of the request methods returns a plain XHR object, which is also available in callbacks. This default XHR object is extended with the following properties:
xhr.requestParameters | Object with passed XHR request parameters |
---|---|
xhr.requestUrl | String with request URL |
Summary
This tutorial is aimed at getting you started with Framework7. Together we have gone through the major parts of Framework7 from its installation to exploring its core components, functionalities and API’s. This will, in general, provide you with a basic understanding of the framework and how to use it for your next HTML based native mobile app. To learn more about Framework7, feel free to check out the official documentation.