Angular JS
No jQuery dependencies, no fat bootstrap js. Just a few angular.js directives super easy to learn to put things together.
Mobile Angular UI follows best practices to improve Angular JS performances and ensure a smooth user experience.
Bootstrap 3 for Mobile
Original Bootstrap 3 stripped out of responsive media queries that are put apart in separate files (just include what you need).
FontAwesome Icons are included by default in place of Glyphicons.Mobile Components
Mobile Angular UI provides essential mobile components that are missing in Bootstrap 3, in particular sidebars, scrollable areas, absolute positioned top and bottom navbars that don't bounce on scroll.
Getting Started
Installation
Either install via bower
or download it
bower install --save mobile-angular-ui
Load files in the head section of your html
<link rel="stylesheet" href="mobile-angular-ui/dist/css/mobile-angular-ui-base.min.css">
<link rel="stylesheet" href="mobile-angular-ui/dist/css/mobile-angular-ui-desktop.min.css">
<script src="angular.min.js">
</script><script src="angular-route.min.js">
</script><script src="mobile-angular-ui/dist/js/mobile-angular-ui.min.js">
</script><script src="mobile-angular-ui/dist/js/mobile-angular-ui-touch-fastclick.min.js">
</script><script src="mobile-angular-ui/dist/js/mobile-angular-ui-scrollable-overthrow.min.js">
</script>
The base
css includes only the mobile css (it has no media queries), while the desktop
css contains just a few lines of code to make sidebars always visible on desktop. So with these two files you can only work with the .*-xs
classes from Bootstrap. If you need more you can include other files from the distribution package to fit your needs. eg. you could add mobile-angular-ui-max-width-767px.css
to use (max-width: 767px)
media queries from Bootstrap.
In the example above some other modules are included along with the core js mobile-angular-ui.min.js
.
mobile-angular-ui.touch
mobile-angular-ui-touch-[implementation].js
provides touch events and swipeLeft
, swipeRight
directives.
Available implemetations are:
-
mobile-angular-ui-touch-fastclick.min.js
(usingfastclick.js
) -
mobile-angular-ui-touch-ng.min.js
(usingangular-touch
)
mobile-angular-ui.scrollable
mobile-angular-ui-scrollable-[implementation].min.js
will enable [scrollable]
directive.
Available implemetations are:
-
mobile-angular-ui-scrollable-overthrow.min.js
(usingoverthrow.js
) -
mobile-angular-ui-scrollable-iscroll.min.js
(usingiscroll
) -
mobile-angular-ui-scrollable-iscroll-lite.min.js
(usingiscroll-lite
)
Initialization
Then you can initialize your Angular application declaring mobile-angular-ui
as a dependence.
angular.module('myApp', ["mobile-angular-ui"]);
This will not load ngRoute, touch events and scrollable modules by default.
A more complete initialization would be like that:
angular.module('myApp', [
"ngRoute",
"mobile-angular-ui",
"mobile-angular-ui.touch",
"mobile-angular-ui.scrollable"
]).config(function($routeProvider) {
$routeProvider.when('/', {
// ...
});
// ...
});
If you wish you can avoid to load mobile-angular-ui
at all and pick a subset of the loaded modules to fit your needs. This is how the mobile-angular-ui
module is defined with its dependencies.
angular.module("mobile-angular-ui", [
'mobile-angular-ui.pointer-events'
'mobile-angular-ui.active-links'
'mobile-angular-ui.directives.toggle'
'mobile-angular-ui.directives.overlay'
'mobile-angular-ui.directives.forms'
'mobile-angular-ui.directives.panels'
'mobile-angular-ui.directives.capture'
'mobile-angular-ui.directives.sidebars'
'mobile-angular-ui.directives.navbars'
]);
Basic Layout
<!-- Sidebars -->
<div class="sidebar sidebar-left" toggleable parent-active-class="sidebar-left-in" id="mainSidebar">
<h1 class="app-name">My App</h1>
<div class="scrollable">
<div class="scrollable-content">
<div class="list-group" toggle="off" bubble target="mainSidebar">
<a class="list-group-item" href="#/">Home <i class="fa fa-chevron-right pull-right"></i></a>
<!-- ... -->
</div>
</div>
</div>
</div>
<div class="app">
<!-- Navbars -->
<div class="navbar navbar-app navbar-absolute-top">
<div class="navbar-brand navbar-brand-center" yield-to="title">
<span>My App</span>
</div>
<div class="btn-group pull-left">
<div ng-click="toggle('mainSidebar')" class="btn btn-navbar sidebar-toggle">
<i class="fa fa-bars"></i> Menu
</div>
</div>
<div class="btn-group pull-right" yield-to="navbarAction">
<div class="btn btn-navbar">
<i class="fa fa-plus"></i> New
</div>
</div>
</div>
<div class="navbar navbar-app navbar-absolute-bottom">
<div class="btn-group justified">
<a href="#/route1" class="btn btn-navbar btn-icon-only"><i class="fa fa-home fa-navbar"></i></a>
<a href="#/route2" class="btn btn-navbar btn-icon-only"><i class="fa fa-list fa-navbar"></i></a>
</div>
</div>
<div class="app-body">
<ng-view class="app-content"></ng-view>
</div>
</div>
Differences with Bootstrap 3
It uses font-awesome in place of glyphicons
responsive css rules for -sm, -md, *-lg are moved out of the default bundle
removed/unsupported components:
- breadcrumbs and pagination: they are just not the best way to navigate a mobile app
- tooltips: unlikely to be useful with small screens and touch devices, popovers should be enough
- modals: are replaced by overlays
Before going ahead with components you may want to familiarize with some basic mobile angular ui directives.
scrollable
First of all: one thing you'll always have to deal with approaching mobile web app development is scroll and position:fixed
bugs.
Due to the lack of support in some devices fixed positioned elements may bounce or disappear during scroll. Also mobile interaction often leverages horizontal scroll eg. in carousels or sliders.
We use scrollable areas to solve any problems related to scroll. Since it is not always available in touch devices we bundle an implementation of scrollable with iScroll or Overthrow.
To use it include either mobile-angular-ui-scrollable-iscroll.js
, mobile-angular-ui-scrollable-iscroll-lite.js
or mobile-angular-ui-scrollable-overthrow.js
.
Markup for any scrollable areas is as simple as:
<div class="scrollable">
<div class="scrollable-content">...</div>
</div>
This piece of code will trigger a directive that properly setup a new iScroll or Overthrow
instance for the .scrollable
node.
toggle
and toggleable
Toggle module is the basic to implement tabs, accordions, collapsibles and all the other components that need to be selectively or exclusively switched on or off.
Toggle module defines two directives: toggle
and toggleable
. These two directives replaces almost all of the bootstrap 3 jquery stuffs.
A [toggle]
node will works as a trigger to turn on
or off
one or more targeted [toggleable]
nodes by translating clicks into toggle events.
toggle directive parameters
| |
---|---|
toggle |
Possible values are on , off or toggle (default to toggle )
|
target |
The id of the corresponding toggleable. One of target or targetClass is required.
|
targetClass |
The class of the corresponding toggleable. One of target or targetClass is required. Notice that this wont select nodes with dom methods.
|
bubble |
If bubble is set [toggle] does not capture the click event and let it to be propagated to dom.
|
activeClass |
The class the element will acquire when corresponding target is active and that will be removed when target is inactive. Does not affect targetClass .
|
inactiveClass |
The class the element will acquire when corresponding target is inactive and that will be removed when target is active. Does not affect targetClass .
|
parentActiveClass |
The class the parent of the element will acquire when corresponding target is inactive and that will be removed when target is active. Does not affect targetClass .
|
parentInactiveClass |
The class the parent of the element will acquire when corresponding target is inactive and that will be removed when target is active. Does not affect targetClass .
|
toggleable directive parameters
| |
---|---|
exclusionGroup |
Instruct the element to "turn itself off" when another element of the same exclusionGroup is activated.
|
default |
The initial state of the element active or inactive (default to inactive ).
|
activeClass |
The class the element will acquire when is active and that will be removed when is inactive.
|
inactiveClass |
The class the element will acquire when is inactive and that will be removed when is active.
|
parentActiveClass |
The class the parent of the element will acquire when is inactive and that will be removed when is active.
|
parentInactiveClass |
The class the parent of the element will acquire when is inactive and that will be removed when is active.
|
To understand how it works consider the following example:
<p toggleable id="lightbulb" active-class="text-primary" class="text-default">
<i class="fa fa-lightbulb-o"></i>
</p>
<div class="btn-group justified nav-tabs">
<a toggle="toggle" target="lightbulb" active-class="active" class="btn btn-default" href>
Toggle
</a>
<a toggle="on" target="lightbulb" class="btn btn-default" href>
Turn On
</a>
<a toggle="off" target="lightbulb" class="btn btn-default" href>
Turn Off
</a>
</div>
The purpose of this code is to create a black lightbulb
icon getting colored when it turns on. The lightbulb
should be turned on and off by three switches. The first alternates its state, the second turns it on and the latter turns it off.
#lightbulb
is a [toggleable]
that wraps a lightbulb icon in form of font icon. When activated it acquires the text-primary
class, thus being highlighted with the primary color.
The first [toggle]
turns on and off the #lightbulb
depending of its state. It also reflects the #lightbulb
activation since when lightbulb is active it takes the active
class.
Second and third [toggle]
are only sending on
or off
commands to #lightbulb
.
Programmatic API
Toggle module exposes the toggle
and toggleByClass
functions through $rootScope
to interact with [toggleable]
in a programmatic way. This will let you do something like that:
<div ng-swipe-left="toggle('mainSidebar', 'off')" ng-swipe-right="toggle('mainSidebar', 'on')">
<div>
toggle
method takes 2 parameters: the [toggleable]
id and the command to send (one of toggle
, on
or off
).
toggleByClass
method takes also 2 parameters: the [toggleable]
class and the command to send.
contentFor
and yieldTo
The capture module exposes directives to let you extract markup which can be used in other parts of a template.
It provides a way to move or clone a block of markup to other parts of the document.
This method is particularly useful to setup parts of the layout within an angular view. Since blocks of html are transplanted within their original $scope
is easy to create layout interactions depending on the context. Some tipical task you can accomplish with these directives are: setup the navbar title depending on the view or place a submit button for a form inside a navbar.
Usage:
Use yield-to
as a placeholder.
<!-- index.html -->
<div class="navbar">
<div yield-to="title" class="navbar-brand">
<span>Default Title</span>
</div>
</div>
<div class="app-body">
<ng-view class="app-content"></ng-view>
</div>
Use content-for
inside any view to populate the yield-to
content.
<!-- myView.html -->
<div content-for="title">
<span>My View Title</span>
</div>
Since the original scope is preserved you can use directives inside content-for
blocks to interact with the current scope. In the following example we will add a navbar button to submit a form inside a nested view.
<!-- index.html -->
<div class="navbar">
<div yield-to="navbarAction">
</div>
</div>
<div class="app-body">
<ng-view class="app-content"></ng-view>
</div>
<!-- newCustomer.html -->
<form ng-controller="newCustomerController">
<div class="inputs">
<input type="text" ng-model="customer.name">
</div>
<div content-for="navbarAction">
<button ng-click="createCustomer()">
Save
</button>
</div>
</form>
app.controller('newCustomerController', function($scope, Store){
$scope.customer = {};
$scope.createCustomer = function(){
Store.create($scope.customer);
// ...
}
});
If you wish you can also duplicate markup instead of move it. Just add duplicate
parameter to contentFor
directive to specify this behaviour.
<div content-for="navbarAction" duplicate>
<button ng-click="createCustomer()">
Save
</button>
</div>
yieldTo directive parameters
| |
---|---|
yieldTo | An unique name to reference the placeholder. |
[content] |
The default content. Default content is restored each time on $routeChangeStart .
|
contentFor directive parameters
| |
---|---|
contentFor | An unique name to reference the placeholder. |
duplicate | Indicates whether the content should be duplicated instead of moved. |
[content] | The content to take place in the placeholder. |
Components
Navbars
Bootstrap default navbars are awesome for responsive websites, but are not the best to interact with in a small screen. Plus fixed positioning is not an option to create navbars standing in top or bottom of the screen.
Mobile Angular Ui offers an alternative to bootstrap navbars that is better suitable for mobile.
It uses scrollable areas to avoid scroll issues. In the following figure you can see the difference between fixed navbars and navbars with absolute positioning.

Here is the basic markup to achieve this.
<div class="app">
<div class="navbar navbar-app navbar-absolute-top">
<!-- ... -->
</div>
<div class="navbar navbar-app navbar-absolute-bottom">
<!-- ... -->
</div>
<div class="app-body">
<ng-view></ng-view>
</div>
</div>
As you can notice the base class is .navbar-app
while the positioning is obtained adding either .navbar-absolute-top
or .navbar-absolute-bottom
class.
Mobile Navbar Layout
Top navbar in mobile design most of the times follows a clear pattern: a centered title surrounded by one or two action buttons, the back or the menu buttons are two common examples.
Twitter Bootstrap ships with a different arrangement of components for navbars since they are supposed to host an horizontal navigation menu.
.navbar-app
is specifically designed to support this different type of interaction and arrangement.
Consider the following example:
<div class="navbar navbar-app navbar-absolute-top">
<div class="navbar-brand navbar-brand-center">
Navbar Brand
</div>
<div class="btn-group pull-left">
<div class="btn btn-navbar">
Left Action
</div>
</div>
<div class="btn-group pull-right">
<div class="btn btn-navbar">
Right Action
</div>
</div>
</div>
As you can see the markup is pretty straightforward: there is a .navbar-brand
with its new specification, .navbar-brand-center
, that will render the title centered and below the two button groups. Note that .navbar-brand-center
will position the title with absolute positioning ensuring that it will never cover the buttons, which would cause interaction problems.
Sidebar
<div class="sidebar sidebar-left" toggleable parent-active-class="sidebar-left-in" id="mainSidebar">
<h1 class="app-name">Mobile Angular UI</h1>
<div class="scrollable">
<div class="scrollable-content">
<div class="list-group" toggle="off" bubble target="mainSidebar">
<a class="list-group-item" href="#/">Home <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/scroll">Scroll <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/toggle">Toggle <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/tabs">Tabs <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/accordion">Accordion <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/overlay">Overlay <i class="fa fa-chevron-right pull-right"></i></a>
<a class="list-group-item" href="#/forms">Forms <i class="fa fa-chevron-right pull-right"></i></a>
</div>
</div>
</div>
</div>
As you can see sidebars can be placed either in left side or right side adding respectively .sidebar-left
and .sidebar-right
classes.
You should also notice that a sidebar is a toggleable. A sidebar is shown when parent has the .sidebar-[left|right]-in
class moving the above .app
element left or right. .sidebar
and .app
are supposed to be siblings.
The purpose of the toggle
directive for .list-group
is to make the sidebar disappear when a link is clicked or tapped, the bubble
parameter is infact used to let click events be propagated to inner links.
<div class="list-group" toggle="off" bubble target="mainSidebar">
<!-- ... -->
</div>
Sidebars can be toggled using the toggle
directive either as an attribute or programmatically via toggle('sidebarId')
<div class="btn-group pull-left">
<div ng-click="toggle('mainSidebar')" class="btn btn-navbar sidebar-toggle">
<i class="fa fa-bars"></i> Menu
</div>
</div>
Tabs
Tabs component is realized via toggle
and toggleable
directives using exclusion-group
parameter to inactivate other tabs but the active one.
<ul class="nav nav-tabs">
<li><a href="#Tab1" toggle="on" parent-active-class="active">Tab 1</a></li>
<li><a href="#Tab2" toggle="on" parent-active-class="active">Tab 2</a></li>
<li><a href="#Tab3" toggle="on" parent-active-class="active">Tab 3</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane" toggleable active-class="active" default="active" id="Tab1" exclusion-group="myTabs">
<h3 class="page-header">Tab 1</h3>
<p><!-- ... --></p>
</div>
<div class="tab-pane" toggleable active-class="active" id="Tab2" exclusion-group="myTabs">
<h3 class="page-header">Tab 2</h3>
<p><!-- ... --></p>
</div>
<div class="tab-pane" toggleable active-class="active" id="Tab3" exclusion-group="myTabs">
<h3 class="page-header">Tab 3</h3>
<p><!-- ... --></p>
</div>
</div>
<div class="btn-group justified nav-tabs">
<a class="btn btn-default" href="#Tab1" toggle="on" active-class="active">Tab 1
</a>
<a class="btn btn-default" href="#Tab2" toggle="on" active-class="active">Tab 2
</a>
<a class="btn btn-default" href="#Tab3" toggle="on" active-class="active">Tab 3
</a>
</div>
Accordion and Collapse
Accordion component is achieved via toggle
and toggleable
directives. exclusion-group
parameter is used to inactivate other panels but the active one.
<div class="panel-group" id="accordion">
<div class="panel panel-default">
<div class="panel-heading" toggle target="collapseOne">
<h4 class="panel-title">
Collapsible Group Item #1
</h4>
</div>
<div id="collapseOne" toggleable active-class="in" exclusion-group="accordion1" default="active" class="panel-collapse collapse">
<div class="panel-body">
<!-- ... -->
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" toggle target="collapseTwo">
<h4 class="panel-title">
Collapsible Group Item #2
</h4>
</div>
<div id="collapseTwo" toggleable active-class="in" exclusion-group="accordion1" class="panel-collapse collapse">
<div class="panel-body">
<!-- ... -->
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" toggle target="collapseThree">
<h4 class="panel-title">
Collapsible Group Item #3
</h4>
</div>
<div id="collapseThree" toggleable active-class="in" exclusion-group="accordion1" class="panel-collapse collapse">
<div class="panel-body">
<!-- ... -->
</div>
</div>
</div>
</div>
Overlays
An overlay is an attempt to replace modals with a component better following mobile patterns.
This is the basic markup for an overlay
. An overlay
directive implicitly sets up a toggleable
using its argument as id
.
<div overlay="myOverlay">
<h4 class="overlay-title">My Overlay</h4>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem, ex eaque possimus ipsa ab quasi quos corporis consequatur laudantium? Ab assumenda delectus quo velit voluptates doloribus. Earum odit facilis qui.
</p>
<p toggle="off" bubble target="myOverlay">
<span class="btn btn-primary">Ok</span>
<span class="btn btn-default">Cancel</span>
</p>
</div>
Dropdowns
Dropdowns are also achieved with toggle
and toggleable
.
<div class="btn-group pull-right toggleable-dropdown" active-class="open" id="myDropdown" toggleable>
<button type="button" class="btn btn-default dropdown-toggle" toggle target="myDropdown">
<i class="fa fa-gear"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" toggle="off" bubble target="myDropdown">
<li><a href>Action</a></li>
<li><a href>Another action</a></li>
<li><a href>Something else here</a></li>
<li class="divider">
<li><a href>Separated link</a></li>
</ul>
</div>
Carousels
Carousels have the same markup of bootstrap but their behaviour is achieved with 2 functions available to $rootScope
: carouselPrev(id)
and carouselNext(id)
.
This is a basic example that uses ngSwipeLeft
and ngSwipeRight
.
<div id="carousel-example" class="carousel">
<div class="carousel-inner" ng-swipe-left="carouselPrev('carousel-example')" ng-swipe-right="carouselNext('carousel-example')">
<div href="" class="item active">
<div class="carousel-example-content">1</div>
</div>
<div href="" class="item">
<div class="carousel-example-content">2</div>
</div>
<div href="" class="item">
<div class="carousel-example-content">3</div>
</div>
</div>
</div>
To create more fancy effects and touch friendly experience you can use $swipe
service direclty. $swipe
service is provided by angular-touch
and is included in both mobile-angular-ui-touch-fastclick
and mobile-angular-ui-touch-ng
.
This is a more complete example to explain how to build a swipe friendly carousel.
<div id="carousel-example" class="carousel">
<div class="carousel-inner">
<div href="" class="item active" carousel-example-item>
<div class="carousel-example-content">1
<br><small>Swipe me!</small>
</div>
</div>
<div href="" class="item" carousel-example-item>
<div class="carousel-example-content">2
<br><small>Swipe me!</small>
</div>
</div>
<div href="" class="item" carousel-example-item>
<div class="carousel-example-content">3
<br><small>Swipe me!</small>
</div>
</div>
</div>
</div>
Lets define the carouselExampleItem
directive.
app.directive( "carouselExampleItem", function($rootScope, $swipe){
return function(scope, element, attrs){
var startX = null;
var startY = null;
var endAction = "cancel";
var carouselId = element.parent().parent().attr("id");
var translateAndRotate = function(x, y, z, deg){
element[0].style["-webkit-transform"] =
"translate3d("+x+"px,"+ y +"px," + z + "px) rotate("+ deg +"deg)";
element[0].style["-moz-transform"] =
"translate3d("+x+"px," + y +"px," + z + "px) rotate("+ deg +"deg)";
element[0].style["-ms-transform"] =
"translate3d("+x+"px," + y + "px," + z + "px) rotate("+ deg +"deg)";
element[0].style["-o-transform"] =
"translate3d("+x+"px," + y + "px," + z + "px) rotate("+ deg +"deg)";
element[0].style["transform"] =
"translate3d("+x+"px," + y + "px," + z + "px) rotate("+ deg +"deg)";
}
$swipe.bind(element, {
start: function(coords) {
startX = coords.x;
startY = coords.y;
},
cancel: function(e) {
translateAndRotate(0, 0, 0, 0);
e.stopPropagation();
},
end: function(coords, e) {
if (endAction == "prev") {
$rootScope.carouselPrev(carouselId);
} else if (endAction == "next") {
$rootScope.carouselNext(carouselId);
}
translateAndRotate(0, 0, 0, 0);
e.stopPropagation();
},
move: function(coords) {
if( startX != null) {
var deltaX = coords.x - startX;
var deltaXRatio = deltaX / element[0].clientWidth;
if (deltaXRatio > 0.3) {
endAction = "next";
} else if (deltaXRatio < -0.3){
endAction = "prev";
}
translateAndRotate(deltaXRatio * 200, 0, 0, deltaXRatio * 15);
}
}
});
}
});
Now swiping items we will see them moving and rotating. When releasing an item if the swipe lenght was at least 3/10 of the item width then carouselPrev/carouselNext are invoked according to swipe direction.
Toggle Switch

The switch
directive (not to be confused with ng-switch
) lets you create a toggle switch control bound to a boolean ngModel
value.
<switch ng-model="invoice.payed"></switch>
Utils
Justified Blocks
Mobile screens are small and it's common to have 2 or three buttons justified. To achieve this behaviour you can use the .justified
class in any parent block of a group of items. This will apply a table
layout to parent and a table-cell
layout to its children.

Example:
<div class="btn-group justified nav-tabs">
<a class="btn">Tab 1</a>
<a class="btn">Tab 2</a>
<a class="btn">Tab 3</a>
</div>
Form helpers
Mobile angular Ui provides some markup savers to create form inputs.
bs-input
<input type="text" ng-model="invoice.customer" label="Customer" bs-input>
That translates to
<div class="form-group container-fluid">
<div class="row">
<label for="invoice_customer_input" class="control-label col-sm-2">Customer</label>
<div class="col-sm-10">
<input type="text" ng-model="invoice.customer" label="Customer" bs-input="" class="ng-scope ng-pristine ng-valid form-control">
</div>
</div>
</div>
Note that this directive only wraps target element with some html. This lets you apply it to any type of control, even custom one.
So for instance you can apply it to textarea
or switch
as well.
<switch ng-model="invoice.payed" label="Payed" bs-input></switch><textarea type="text" ng-model="customer.mailing_address" label="Address" bs-input></textarea>
Panel Helpers
bs-panel
A super simple directive minimizing the markup to use bootstrap panels.
<div bs-panel title="My Panel">
<!-- Content -->
</div>
That translates to
<div class="panel">
<div class="panel-heading">
<h2 class="panel-title">
My Panel
</h2>
</div>
<div class="panel-body">
<!-- Content -->
</div>
</div>