Improve this

Theming

Onsen UI style can be easily modified in a variety of ways. Here are the most common options.

Modifiers

A modifier is a cross-component way to provide customizability for Onsen UI components in the shape of custom attributes. When a component is defined with a modifier, it will have a separate class namespace so that you can apply custom styles to the component. Some components have several easy to use preset modifiers to change the appearance.

For example, each of the following buttons have a different look. To change modifiers dynamically, please manipulate modifier attribute from JavaScript.

<ons-button modifier="quiet">Quiet</ons-button>
<ons-button modifier="light">Light</ons-button>
<ons-button modifier="large">Large</ons-button>
<ons-button modifier="cta">Call To Action</ons-button>
<ons-button modifier="material">Material Design</ons-button>

For further information, please have a look at this article.

Cross Platform Styling (Autostyling)

Onsen UI components are automatically styled depending on the platform where the app runs. You can easily test this feature with your browser Dev Tools by switching between iOS and Android views or by appending ?platform=android or ?platform=ios as a query string to the URL.

Automatic styling simply applies modifier="material" to the components when ons.platform.isAndroid() is true. You can disable this feature by running ons.disableAutoStyling() right after including onsenui.js (i.e. before the app is initialized). If you disable it you may need to manually specify modifier="material" in every component you want to display with Material Design. You can also specify disable-auto-styling attribute in specific components that you don’t want to auto style.

Some tools are provided to give a more accurate customization.

Platform utilities

ons.platform object is available with methods such as ons.platform.isIOS(), ons.platform.isWebView(), etc.

You can set a platform with ons.platform.select('android'), for example, in order to display Material Design on every platform. This must be called before the app is initialized (right after including onsenui.js).

Conditional element

A conditional element called ons-if is available to filter content depending on the platform or orientation.

<ons-if> component is not available for React and Vue bindings.

  <ons-if platform="android">
    This is Android
  </ons-if>
  <ons-if platform="ios other">
    This is NOT Android
  </ons-if>

With this, for example, you can display ons-fab for Material Design and other type of button for iOS flat design.

AngularJS 1 bindings also provide ons-if-platform for this purpose:

<div ons-if-platform="android">
  This is Android
</div>
Icons shortcut

ons-icon provides a shortcut to make auto styling easier:

<ons-icon icon="ion-navicon, material:md-menu" size="24px, material:20px"></ons-icon>

The second icon will be displayed when material modifier is present (other modifiers can be used).

Applying Styles to Inner Custom Elements

Most Onsen UI components expand the inner element during runtime. For instance, ons-page automatically injects the following code inside <ons-page> and </ons-page>.

<ons-page class="page">
  <div class=”page__background”></div>
  <div class=”page__content”><!-- Your page content --></div>
</ons-page>

Notice some additional attributes (such as class=”page”) and elements (such as div) are added.

However, you can avoid this behavior by writing the auto-inserted attributes or elements manually.

If you write the following code,

<ons-page>
  <div class=”page__content”><!-- Your page content --></div>
</ons-page>

Onsen UI compiles the code above into the following code without adding new <div class=”page__content”>

<ons-page class="page">
  <div class=”page__background”></div>
  <div class=”page__content”><!-- Your page content --></div>
</ons-page>

but <div class=”page__background”> will be added since no <div class=”page__background”> is placed.

Understanding how to bypass compilation is important if you want to attach style to div, which means you can write:

<ons-page>
  <div class=”page__background” style=”background-color: #000;”></div>
  <div class=”page__content” style=”color: #ccc;”><!-- Your page content --></div>
</ons-page>
Pitfalls: Specially treated tags in compilation

<ons-toolbar>, <ons-bottom-toolbar> and some tags are treated specially in compilation.

For example,

<ons-page>
  <ons-toolbar>
    <div class="center">Title</div>
  </ons-toolbar>

  <!-- Your page content -->
</ons-page>

will be compiled into

<ons-page class="page">
  <ons-toolbar class="toolbar">
    <div class="center toolbar__center toolbar__title">Title</div>
  </ons-toolbar>

  <div class="page__background"></div>
  <div class="page__content"><!-- Your page content --></div>
</ons-page>

You can notice that <ons-toolbar> is never moved into <div class="page__content">.

Some components have behaviours such as these, so make sure to keep that in mind.

アニメーションを拡張する

Onsen UI already provides multiple built-in animations for its routing components and dialogs. However, it is also possible to create custom animations for specific components or even extend existing animations and change part of them. This is a relatively advanced topic since it requires digging a bit in Onsen UI core code.

Animit

Onsen UI relies on Animit, a minimal animation library for managing CSS transtions on mobile browsers.

Animit can be accessed with ons.animit or import { animit } from ons;, depending on the type of the app. It exposes methods to queue CSS animations, apply delays and run callbacks as follows:

let animation1 = animit(myElement) // This defines the animation for the provided element
  .saveStyle() // Saves the original style of the element
  .queue({ // Original position/style in the animation
    css: {
      transform: 'translate3D(0, 100%, 0)'
    },
    duration: 0
  })
  .wait(0.2) // Delay applied before the transition starts
  .queue({ // Next step in the animation
    css: {
      transform: 'translate3D(0, 0, 0)',
    },
    duration: 0.6,
    timing: 'linear'
  })
  .restoreStyle() // Restores the original style of the element
  .queue(done => { // Optional "On transition end" callback
    callback();
    done();
  }
);

animation1.play(); // Run the animation

Since Animit modifies the element’s style property, it provides saveStyle() and restoreStyle() methods to ensure the previous styles are not lost. queue({css: {...}, duration: 0, timing: 'linear'}) or queue({...}, {duration: 0, timing: 'linear'}) method is provided to add transitions to the queue. The first one will be the first style applied in the animation that will transition into the following styles. In the provided example, we are moving a new page inside the view from right to left. Therefore, it needs to start at position translate3d(0, 100%, 0) and move to translate3d(0, 0, 0). Method wait(...) can be used to apply a delay between transitions. Finally, we can optionally call queue(function(done) { ...; done(); }) again to run a callback if necessary.

It is also possible to pass an array of HTML elements to animit if performing the same animation on multiple elements is required: animit([el1, el2]).saveStyle()....

It is very common to have more than one animation running at the same time. animit.runAll(animation1, animation2, animation3); method can be used for this behavior instead of animation1.play(); animation2.play(); animation3.play();.

Creating animators

Animators can be created from scratch by extending the necessary animator classes that Onsen UI provides. Every component exposes a minimum animator interface that must be extended and implemented: NavigatorTransitionAnimator, AlertDialogAnimator, DialogAnimator, PopoverAnimator, ModalAnimator, TabbarAnimator and SplitterAnimator. This is the desired way to implement animators if you want to build a custom version of Onsen UI or want to make a pull request to the repository. For more information, please have a look at the existing animators for every component.

ES2015 (ES6) is preffered but not strictly required for this to work. An example in ES5 can be found here.

Extending animators

Another way to make new animators is extending an existing animator and modifiying part of its behavior (or all). This is in general easier if you just want to tweak the appearance or timing, or even if you want to create a whole new thing starting from another animator. For this it is also required to have a look at the existing animators, choose one and check its properties and methods. Every animator provides a extend({...}) class method that returns a new animator. Animators are exposed in every component class: ons.NavigatorElement.animators or ons.AlertDialogElement.animators are some examples. These objects contain all the registered animators and can be extended as follows.

var fadeIOS = ons.NavigatorElement.animators['fade-ios'];
var customAnimator = fadeIOS.extend({
  timing: 'cubic-bezier(.1, .7, .1, 1)',
  delay: 0.1,
  push: function(enterPage, leavePage, callback) {
    ons.animit.runAll(
      ons.animit(enterPage)...,
      ons.animit(leavePage)...
    );
  }
});

// This step is mandatory
ons.NavigatorElement.registerAnimator('customAnimationName', customAnimator);

This overwrites the push animation but uses the original pop animation. timing and delay properties will still affect both animations. Some animators have extra properties, such as backgroundMask. Please check the animator you want to extend to see all the properties.

After the new animator is created and registered, we can simply specify the animation with its name: myNavigator.pushPage('page.html', {animation: 'customAnimationName'}). Or make it default: <ons-navigator animation="customAnimationName">. The same applies to the other components.