Creating a jide.js switch control

As some of you might know already, I have been working hard to create a new kind of UI toolkit for the web: jide.js.

Last week, we have released version 1.0.0-beta2. In the future, I will regularly blog about jide.js and show examples of what can be done with it.

Now, before we discuss todays example, a “Switch” control as known from iOS (and adapted from Switchery), please read the Yeoman Quickstart to learn how to set up a new jide.js project in seconds.

All done? Great, now let’s get started with the control.

What do we need?

Now, this control should be simple. We’ll use the DOM structure and most of the CSS from the Switchery project. When it comes to the properties we need, let’s keep it simple, too. A Switch can either be checked, or not. We might also want the ability to display some text depending on its checked state.

That’s a total of three properties: checked, checkedText, uncheckedText.

The Switch control and it’s Skin

define([
  'jidejs/base/Class',
  'jidejs/base/ObservableProperty',
  'jidejs/ui/Control',
  'jidejs/ui/Skin',
  'text!./Switch.html'
], function(
  Class, ObservableProperty,
  Control, Skin,
  SwitchTemplate
) {
  function Switch(config) {
    installer(this);
    Control.call(this, config || {});
    this.classList.add('jide-extra-switch');
  }
  Class(Switch).extends(Control).def({
    checked: false,
    checkedText: null,
    uncheckedText: null
  });
  var installer = ObservableProperty.install(Switch, 'checked', 'checkedText', 'uncheckedText');

  // this is the standard Skin implementation
  Switch.Skin = Skin.create(Skin, {
    template: SwitchTemplate,

    toggleCheckedState: function() {
      var toggle = this.component;
      toggle.checked = !toggle.checked;
    }
  });

  return Switch;
});

The Template

<template bind="
  css: {
    'is-checked': component.checked
  },
  on: {
    click: toggleCheckedState.bind($item)
  }
">

  <small pseudo="x-checkmark" bind="
    text: component.checked ? component.checkedText : component.uncheckedText
  "></small>

</template>

As you can see, we take full advantage of the new features of jide.js 1.0.0-beta2 and use a template with embedded data binding to define the DOM structure of our control.

The css binding will add or remove the is-checked CSS class to or from the element, depending on whether or not it is currently checked. When the user clicks on the Switch, its checked state will be toggled.

The CSS

Now all that is left is some CSS to style the Switch control. For jide.js, it is common to use LESS instead of pure CSS. The CSS/LESS is the most verbose part of this control, so don’t be too shocked by its length.

.jide-extra-switch {
  .background(@base, @border, @highlight, @checkmark) {
    background: @base;
    border: 1px solid @border;
    .box-shadow(@border 0px 0px 0px 0px inset);

    &::x-checkmark, & > .x-checkmark {
      background: @checkmark;
      color: @highlight;
    }

    &.is-checked {
      background: @highlight;
      border-color: @highlight;
      .box-shadow(@highlight 0px 0px 0px 16px inset);
    }
  }

  .jide-extra-switch > .background(@inverse, @silver, @lightgray, @inverse);

  border-radius: 20px;
  cursor: pointer;
  display: inline-block;
  height: 32px;
  position: relative;
  vertical-align: middle;
  width: 52px;
  .transition("border 0.4s, box-shadow 0.4s, background-color 1.2s");

  &::x-checkmark, & > .x-checkmark {
    .box-sizing(border-box);
    text-align: center;
    padding: 7px 0;
    border-radius: 100%;
    .box-shadow(0 1px 3px rgba(0, 0, 0, 0.4));
    height: 30px;
    width: 30px;
    position: absolute;
    top: 0;
    left: 0px;
    .transition(left 0.2s);
  }

  &.is-checked {
    &::x-checkmark, & > .x-checkmark {
      left: 20px;
    }
  }

  &.primary {
    .jide-extra-switch > .background(@inverse, @silver, @firm, @inverse);
  }
  &.info {
    .jide-extra-switch > .background(@inverse, @silver, @info, @inverse);
  }
  &.danger {
    .jide-extra-switch > .background(@inverse, @silver, @danger, @inverse);
  }
  &.success {
    .jide-extra-switch > .background(@inverse, @silver, @success, @inverse);
  }
  &.warning {
    .jide-extra-switch > .background(@inverse, @silver, @warning, @inverse);
  }
  &.inverse {
    .jide-extra-switch > .background(@inverse, @silver, @base, @inverse);
  }
}

Now, let’s see what this looks like in practice.

require(['jidejs-extra/control/Switch'], function(Switch} {
    document.body.appendChild(new Switch({checked: true, checkedText: 'Yes', uncheckedText: 'No'}).element);
    document.body.appendChild(new Switch({classList: ['primary'], checked: true, checkedText: 'On', uncheckedText: 'Off'}).element);
    document.body.appendChild(new Switch({classList: ['info'], checked: true}).element);
    document.body.appendChild(new Switch({classList: ['danger'], checked: true}).element);
    document.body.appendChild(new Switch({classList: ['success'], checked: true}).element);
    document.body.appendChild(new Switch({classList: ['warning'], checked: true}).element);
    document.body.appendChild(new Switch({classList: ['inverse'], checked: true}).element);
});

Live example

Get full source code

In case you don’t want to create this control yourself, just grab a copy on Github from jidejs-extra.

Leave a Reply

Your email address will not be published. Required fields are marked *