Getting started with Framework 7: An HTML framework for building mobile apps

framework-7.png

This tutorial introduces Framework 7, an open source mobile HTML framework. It walks you through installing the framework and creating a simple sample app, exploring Framework 7 features along the way.

Introduction

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:

1import 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:

1// Import core framework
2    import Framework7 from 'framework7';
3
4    // Import additional components
5    import Searchbar from 'framework7/components/searchbar/searchbar.js';
6
7    // Install F7 Components using .use() method on class:
8    Framework7.use([Searchbar]);
9
10    // Init app
11    var app = new Framework({/*...*/});

Such modular structure provides best widget tree structure and package size optimization. In addition to default export, it has named export for Template7, Dom7, Request, Device, Utils and Support libraries:

1import Framework7, { Device, Request } from 'framework7';
2
3    var app = new Framework({/*...*/});
4
5    if (Device.ios) {
6      Request.get('http://google.com');
7    }

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:

1<!DOCTYPE html>
2    <html>
3      <head>
4        <!-- Required meta tags-->
5
6        <meta charset="utf-8">
7        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
8        <meta name="apple-mobile-web-app-capable" content="yes">
9
10        <!-- Color theme for statusbar -->
11        <meta name="theme-color" content="#2196f3">
12
13        <!-- Your app title -->
14        <title>My App</title>
15
16        <!-- Path to Framework7 Library CSS -->
17        <link rel="stylesheet" href="path/to/framework7.min.css">
18
19        <!-- Path to your custom app styles-->
20        <link rel="stylesheet" href="path/to/my-app.css">
21      </head>
22      <body>
23
24        <!-- App root element -->
25        <div id="app">
26
27          <!-- Statusbar overlay -->
28          <div class="statusbar"></div>
29
30          <!-- Your main view, should have "view-main" class -->
31          <div class="view view-main">
32
33            <!-- Initial Page, "data-name" contains page name -->
34            <div data-name="home" class="page">
35
36              <!-- Top Navbar -->
37              <div class="navbar">
38                <div class="navbar-inner">
39                  <div class="title">Awesome App</div>
40                </div>
41              </div>
42
43              <!-- Toolbar -->
44              <div class="toolbar">
45                <div class="toolbar-inner">
46                  <!-- Toolbar links -->
47                  <a href="#" class="link">Link 1</a>
48                  <a href="#" class="link">Link 2</a>
49                </div>
50              </div>
51
52              <!-- Scrollable page content -->
53              <div class="page-content">
54                <p>Page content goes here</p>
55                <!-- Link to another page -->
56                <a href="/about/">About app</a>
57              </div>
58            </div>
59          </div>
60        </div>
61
62        <!-- Path to Framework7 Library JS-->
63        <script type="text/javascript" src="path/to/framework7.min.js"></script>
64
65        <!-- Path to your app js-->
66        <script type="text/javascript" src="path/to/my-app.js"></script>
67      </body>
68    </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:

1var 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:

1var app = new Framework7({
2      // App root element
3      root: '#app',
4      // App Name
5      name: 'My App',
6      // App id
7      id: 'com.myapp.test',
8      // Enable swipe panel
9      panel: {
10        swipe: 'left',
11      },
12      // Add default routes
13      routes: [
14        {
15          path: '/about/',
16          url: 'about.html',
17        },
18      ],
19      // ... other parameters
20    });

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:

1var mainView = app.views.create('.view-main');

So your final initialization code in my-app.js could look like:

1var app = new Framework7({
2      // App root element
3      root: '#app',
4      // App Name
5      name: 'My App',
6      // App id
7      id: 'com.myapp.test',
8      // Enable swipe panel
9      panel: {
10        swipe: 'left',
11      },
12      // Add default routes
13      routes: [
14        {
15          path: '/about/',
16          url: 'about.html',
17        },
18      ],
19      // ... other parameters
20    });
21
22    var mainView = app.views.create('.view-main');

Ok, now we know how to scaffold and initialize the app, lets 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:

1var app = new Framework7({
2      ...
3      on: {
4        // each object key means same name event handler
5        pageInit: function (page) {
6          // do something on page init
7        },
8        popupOpen: function (popup) {
9          // do something on popup open
10        },
11      },
12    });

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 event handler that will be removed after it was fired
[instance].off(event)Remove all handlers for specified event
[instance].emit(event, …args)Fire event on instance

Adding event handlers

Here is how you add event handlers in Framework7:

1var app = new Framework7({/*...*/});
2
3    var popup = app.popup.create({/*...*/});
4
5    app.on('pageInit', function (page) {
6      // do something on page init
7    });
8
9    popup.on('open', function (popup) {
10      // do something on popup open
11    });
12
13    // The `once` handler will only work once
14    popup.once('close', function (popup) {
15      // do something on popup close
16    });

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:

1app.on('popupOpen popupClose', function (popup) {
2      // do something on popupOpen and popupClose
3    });

Remove event handlers

In Framework7, named function handlers can be removed:

1function onTabShow() {
2      // do something on tab show
3    }
4
5    // add handler
6    app.on('tabShow', onTabShow);
7
8    // later remove tabShow handler:
9    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:

1// Remove all tabShow handlers
2    app.off('tabShow');

Emit events

And of course we can emit events and any kind of custom events we may need:

1app.on('myCustomEvent', function (a, b) {
2      console.log(a); // -> 'foo'
3      console.log(b); // -> 'bar'
4    });
5
6    app.emit('myCustomEvent', 'foo', 'bar');

Event handler context

Event handler context (this) always points to the instance where it was assigned:

1app.on('popupOpen', function () {
2      console.log(this); // -> app instance
3    });
4    popup.on('popupOpen', function () {
5      console.log(this); // -> popup instance
6    });

Router/Navigation

Routes

When you initialize the Framework7 app, you should pass default routes using the routes array parameter:

1var app = new Framework7({
2      routes: [
3        {
4          name: 'about',
5          path: '/about/',
6          url: './pages/about.html',
7        },

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:

1var view1 = app.views.create('.view-1', {
2      routes: [
3        {
4          path: '/users/',
5          url: './pages/users.html',
6        },
7        {
8          path: '/user/',
9          url: './pages/user.html',
10        },
11      ],
12    });

Route properties

Let’s now see what each route property means:

ParameterTypeDescription
namestringRoute name, e.g. home
pathstringRoute 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
optionsobjectObject with additional route options (optional)
routesarrayArray with nested routes

The following route properties define how (from where/what) content should be loaded:

elHTMLElementLoad page from DOM bypassed HTMLElement
pageNamestringLoad page from DOM that has same data-name attribute
contentstringCreates a dynamic page from specified content string
urlstringLoad 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 regular expression like:

1// Default route, match to all pages (e.g. 404 page)
2    {
3      path: '(.*)',
4      url: './pages/404.html',
5    },

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.appLink to global app instance
router.viewLink to related View instance
router.paramsObject with router initialization parameters
router.elRouter’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 previous page, going back in View history
– url string – url to navigate to (optional).
– options
router.refreshPage()Refresh/reload 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 event handler that will be removed after it was fired
router.off(event, handler)Remove event handler
router.off(event)Remove all handlers for specified event
router.emit(event, …args)Fire event on 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:

1<!-- same as router.navigate('/somepage/'); -->
2    <a href="/somepage/">Some Page</a>
3
4    <!-- same as router.navigate('/somepage/', {reloadCurrent: true, animate: false}); -->
5    <a href="/somepage/" data-animate="false" data-reload-current="true">Some Page</a>
6
7    <!-- same as router.back(); -->
8    <a href="#" class="back">Go back</a>
9
10    <!-- same as router.back('/home/', {force: true, ignoreCache: true}); -->
11    <a href="/home/" data-force="true" data-ignore-cache="true" class="back">Go back</a>

Links default behavior:

  • If a link is in inside of a not-initialized view, then it will load page in main view
  • If a link is in inside of an initialized view, then it will load page in this view (if other view is not specified in view’s linksView parameter)

But if we need to load page in another view we can specify this view’s CSS selector in link’s data-view attribute

1<!-- left view -->
2    <div class="view view-init view-left" data-name="left">
3      ...
4      <!-- will load "some-page" to main view -->
5      <a href="/some-page/" data-view=".view-main">Some Page</a>
6      ...
7    </div>
8    <!-- main view -->
9    <div class="view view-init view-main">
10      ...
11      <!-- will load "another-page" to left view -->
12      <a href="/another-page/" data-view=".view-left">Another Page</a>
13      ...
14    </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):

PropertyTypeDescription
templatestringTemplate7 template string. Will be compiled as Template7 template
renderfunctionRender function to render component. Must return full html string or HTMLElement
datafunctionComponent data, 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-edgesAdd to element that is stick to left/right screen edges in landscape orientation.
ios-left-edgeAdd to element that is stick to the left screen edge in landscape orientation.
ios-right-edgeAdd to element that is stick to the right screen edge in landscape orientation.
no-ios-edgesAdd to element which is inside of ios-edges to remove additional horizontal spacing.
no-ios-left-edgeAdd to element which is inside of ios-edges to remove additional left spacing.
no-ios-right-edgeAdd to 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 as element that is stick to the left screen edge and requires extra spacing on left side
  • Right Panel – already considered as element that is stick to the right screen edge and requires extra spacing on right side

Here is the example app layout with such classes:

1<body>
2      <!-- app root -->
3      <div id="app">
4        <!-- statusbar -->
5        <div class="statusbar"></div>
6
7        <!-- left panel doesn't require any additional classes -->
8        <div class="panel panel-left panel-cover">
9          ...
10        </div>
11
12        <!-- right panel doesn't require any additional classes -->
13        <div class="panel panel-right panel-reveal">
14          ...
15        </div>
16
17        <!-- main view, full-wide element, add "ios-edges" class -->
18        <div class="view view-main view-init ios-edges" data-url="/">
19          <div class="page">
20            <div class="navbar">
21              ...
22            </div>
23            <div class="page-content">
24              <!-- full-wide list, will inherit ios-edges from view -->
25              <div class="list">
26                ...
27              </div>
28              <!-- full-wide content block, will inherit ios-edges from view -->
29              <div class="block">
30                ...
31              </div>
32              <!--
33                two-columns blocks: need to
34                  - remove extra spacing on right side for left block
35                  - remove extra spacing on left side for right block
36              -->
37              <div class="row">
38                <!-- remove right spacing on left block -->
39                <div class="block col no-ios-right-edge">
40                  ...
41                </div>
42                <!-- remove left spacing on right block -->
43                <div class="block col no-ios-left-edge">
44                  ...
45                </div>
46              </div>
47              ...
48            </div>
49          </div>
50        </div>
51      </div>
52      <script src="../packages/core/js/framework7.min.js"></script>
53      <script src="js/routes.js"></script>
54      <script src="js/app.js"></script>
55    </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.

ColoriOSMD
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:

1<body class="color-theme-red">
2        ...
3    </body>
4
5    <div class="page color-theme-green">
6        ...
7    </div>
8
9    <div class="list-block color-theme-pink">
10        ...
11    </div>
12
13    <div class="navbar color-theme-orange">
14        ...
15    </div>
16
17    <div class="segmented color-theme-yellow">
18        ...
19    </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:

1<body class="theme-dark">
2        ...
3    </body>
4
5    <div class="page theme-dark">
6        ...
7    </div>
8
9    <div class="list-block theme-dark">
10        ...
11    </div>

Helper classes

There are also additional helper classes that could be used without/outside color themes:

color-[color] – if you want to change color of individual button, link or icon, for example:
<a class="button color-red">Red button</a>

text-color-[color] – if you want to change text color of required element:
<p class="text-color-red">Red color text</p>

bg-color-[color] – if you want to quickly set 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:

1//Export DOM7 to local variable to make it easily accessible
2    var $$ = Dom7;
3
4### Usage example
5
6Just everything you already know:
7
8``` language-javascript
9    $$('.something').on('click', function (e) {
10        $$(this).addClass('hello').attr('title', 'world').insertAfter('.something-else');
11    });

Available methods

All these methods work almost in the same way and with the same arguments as in jQuery or Zepto:

1$$(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:

1// Initialize app
2    var app = new Framework7();
3
4    var $$ = Dom7;
5
6    // Compile templates once on app load/init
7    var searchTemplate = $$('script#search-template').html();
8    var compiledSearchTemplate = Template7.compile(searchTemplate);
9
10    var listTemplate = $$('script#list-template').html();
11    var compiledListTemplate = Template7.compile(listTemplate);
12
13    // That is all, now and further just execute compiled templates with required context
14    app.on('pageInit', function (page) {
15        // Just execute compiled search template with required content:
16        var html = compiledSearchTemplate({/*...some data...*/});
17
18        // Do something with html...
19    });

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):

1// If you need it in a place where you don't have access to app instance or before you init the app, do:
2
3    Framework7.request.get('somepage.html', function (data) {
4      console.log(data);
5    });
6
7
8    // After you init the app, you can access it as app instance property:
9    var app = new Framework7({ /*...*/ });
10
11    app.request.get('somepage.html', function (data) {
12      console.log(data);
13    });

To load data from the server use:

1app.request(parameters)

where:
parameters = object – Request parameters.
Returns plain XHR object.

In Framework7, To load data from the server use:

1Framework7.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

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:

1var app = new Framework7();
2
3    var $$ = Dom7;
4
5    app.request.get('blog-post.php', { foo:'bar', id:5 }, function (data) {
6      $$('.articles').html(data);
7      console.log('Load was performed');
8    });

Post

To load data from the server using a HTTP POST request use: F``ramework7.request.post(url, data, success, error, dataType).
The request returns a plain XHR object.
For example:

1var app = new Framework7();
2
3    var $$ = Dom7;
4
5    app.request.post('auth.php', { username:'foo', password: 'bar' }, function (data) {
6      $$('.login').html(data);
7      console.log('Load was performed');
8    });

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:

1Framework7.request.json('items.json', function (data) {
2      console.log(data);
3    });
4
5    var app = new Framework7();
6
7    app.request.json('users.json', function (data) {
8      console.log(data);
9    });

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:

1var app = new Framework7();
2
3    var $$ = Dom7;
4
5    app.request.postJSON('http://api.myapp.com', { username:'foo', password: 'bar' }, function (data) {
6      console.log(data);
7    });

Request setup

Framework7.request.setup(parameters) – set default values for future Ajax requests.
For example:

1// After the following setup all XHR requests will have an additional 'Autorization' header
2    Framework7.request.setup({
3      headers: {
4        'Authorization': 'sometokenvalue'
5      }
6    })

Original request parameters

Each of the request methods returns plain XHR object, which is also available in callbacks. This default XHR object is extended with the following properties:

xhr.requestParametersObject with passed XHR request parameters
xhr.requestUrlString 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.

Build the chat app using Framework 7 by following this tutorial