JavaScript
Article
By Giulio Mainardi

Quick Tip: Use Bootstrap Components without jQuery

By Giulio Mainardi
Last chance to win! You'll get a... FREE 6-Month Subscription to SitePoint Premium Plus you'll go in the draw to WIN a new Macbook SitePoint 2017 Survey Yes, let's Do this It only takes 5 min

This article was peer reviewed by Joan Yin. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Do you use Bootstrap’s JavaScript components? Do you like Vanilla JavaScript? Then you might be interested in the Native JavaScript for Bootstrap project, which aims to remove the jQuery dependency required by the components by porting them to plain JavaScript.

Why?

The motivations of such a port are mostly related to performance.

One benefit is the potential performance gain that can come from the superior execution speed of plain JavaScript over jQuery, as reported in many benchmarks.

Another performance advantage is the reduced page weight. Let’s make a quick comparison. All the numbers below refers to minified gzipped files and are expressed in KBs. bootstrap.js refers to the original Bootstrap scripts, bsn.js to the Bootstrap Native scripts, and jq to jQuery. Here we are looking at the bundled files that gather together all the components, but it should be noted that both libraries have a modular structure that allows the loading of only the needed components and their dependencies.

Bootstrap.js:

  • jq 3.1.0 + bootstrap.js = 34.5 + 11.2 = 45.7
  • jq 3.1.0 slim + bootstrap.js = 27.2 + 11.2 = 38.4
  • jq 2.2.4 + bootstrap.js = 34.3 + 11.2 = 45.5
  • jq 1.12.4 + bootstrap.js = 38.8 + 11.2 = 50.0

Native JavaScript for Bootstrap:

  • minifill + bsn.js = 2.4 + 7.8 = 10.2
  • polyfill.io(on chrome 54) + bsn.js = 1.1 + 7.8 = 8.9
  • polyfill.io(on IE 8) + bsn.js = 12.1 + 7.8 = 19.9

(The polyfill.io size for IE8 was taken from here. These polyfills are discussed in the next sections)

Bar chart comparing bundle sizes of Bootstrap to Bootstrap Native

So, with the Bootstrap components the size varies over the range [38.4, 50.0] KB, while with Bootstrap Native the range shrinks to [8.9, 19.9] KB.

Browser Support

Regarding browser support, it is comparable to the original Bootstrap jQuery-based script, that is, it supports the latest browsers on the major mobile and desktop platforms and IE8+. This is accomplished by means of two polyfill strategies.

The first revolves around the use of the Polyfill.io service. All you have to do is insert the relative script tag in the document to get a set of polyfills tailored to each browser:

<script src="https://cdn.polyfill.io/v2/polyfill.js"></script>

The service can be configured to customize its response based on the features really used on the site. See the Pollyfill.io documentation for details.

Alternatively, it is possible to use minifill, a potentially lighter custom polyfill supplied by the project author itself.

--ADVERTISEMENT--

Usage

The usage is similar to the original Bootstrap scripts, except we’ll remove jQuery, replace the Bootstrap scripts with the ones supplied by the project, and, if necessary, include the polyfills.

So, before the end </body> tag we include the script for the components:

<script src="https://cdn.jsdelivr.net/bootstrap.native/1.0.4/bootstrap-native.js"></script>

Other CDN URLs are available and listed on the documentation page. Alternatively, the file can be downloaded and served locally.

If the polyfills are needed, they should be included in the <head> tag:

<script src="https://cdn.jsdelivr.net/minifill/0.0.3/minifill.min.js"> </script>
<!--[if IE]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<![endif]-->

This snippet employs the minifill polyfill.

See the project documentation page for more detailed usage instructions.

A Port?

To be precise, it is not a literal port that replicates all the features of the original scripts. The author deliberately chose to leave out some slight functionality, particularly lesser used features, mainly for performance reasons and to simplify the development.

Let’s take a look at some of these issues.

The custom events

These are the events triggered by many Bootstrap components during their life cycle. For example, a Modal fires two events, one when it is opened and the other when it is closed (actually, two events are fired in each case, one before ('show') and the other ('shown') after the action).
Similar events are employed by a Tab to notify its observers when there is a tab switch: a hide event is dispatched for the current tab and a show event for the tab that have to be shown.

Bootstrap Native, instead, provides these events only for the Carousel and the Button. The original Carousel triggers a couple of custom events when there is a transition between two slides. The first event, 'slide', is fired just before the transition begins, while the other one, 'slid', is fired after the transition has completed. The event object passed to the handlers has two properties that supply information about the transition, direction, and relatedTarget.

The following jQuery snippet illustrates:

$carousel
  .on('slide.bs.carousel', function(e) {
    var caption = $(e.relatedTarget).find('.carousel-caption').text();
    console.log('About to slide to the ' + e.direction + ' to slide ' +  caption);
  })
  .on('slid.bs.carousel', function(e) {
    var caption = $(e.relatedTarget).find('.carousel-caption').text();
    console.log('Slid to the ' + e.direction + ' to slide ' + caption);
  });

Bootstrap Native supports both events, but the event object doesn’t have the direction and relatedTarget properties. We can translate the previous snippet to vanilla JS in this way:

carousel.addEventListener('slide.bs.carousel', function(e) {
  console.log('About to slide');
});

carousel.addEventListener('slid.bs.carousel', function(e) {
  console.log('Slid');
});

What about if we need the custom events for some other component? It is not too difficult to implement them ourselves. We can refer to the Bootstrap Native Carousel code and use the CustomEvent API.

First create the event objects:

if (('CustomEvent' in window) && window.dispatchEvent) {
  slid =  new CustomEvent("slid.bs.carousel");
  slide = new CustomEvent("slide.bs.carousel");
}

When a slide transition is about to start, the ‘slide’ event is fired:

if (slide) {
  this.carousel.dispatchEvent(slide);
} 

And, finally, when the transition has finished, the ‘slid’ event is triggered:

if (slid) {
  self.carousel.dispatchEvent(slid);
}

Based on this model, a similar code can be easily added to other components.

The CustomEvent API is not readily available on every browser, but the aforementioned polyfills cover it.

The programmatic API

This is the API Bootstrap components expose to allow their initialization and control with JavaScript. For example, on a Modal element three methods can be invoked to control its visibility:

$('#mymodal').modal('show')
$('#mymodal').modal('hide')
$('#mymodal').modal('toggle')

Bootstrap Native instead, often doesn’t provide these programmatic control. The above methods are not available for the Modal, nor for the Dropdown, Tab, Alert, or Carousel.

Other differences

If we perform a side-by-side comparison of the components, it is clear how Bootstrap Native it is not a literal port, and in some cases removes functionality, while in others it adds something new.

In the Tooltip, for instance, with Bootstrap we have to explicitly init them, because, for performance reasons, the relative data-api is opt-in. In Bootstrap Native, as long as the DATA API attributes are properly set, the initialization is automatic. Additionally, the Native version can automatically place the tooltip, without any additional options. But it doesn’t cover a template system like the one provided by Bootstrap.

The dropdown furnishes another example of a slight difference with respect to the relative Bootstrap component due to a deliberate implementation choice. The jQuery dropdown menu closes after a click on a menu item, while the Native menu remains open.

Keyboard input handling is also incomplete. The tab navigation works, but other operations are partially implemented.

In the Modal, the remote option, used to specify a source for content to be loaded in the component, is not available, but there is a template system for dynamic content.

Regarding the Carousel, the jQuery component responds to keyboard inputs by default, while in the vanilla version this behavior must be enabled using the data-keyboard attribute:

<div id="carousel" class="carousel slide" ... data-keyboard="true">

Another difference for this component is in how the duration option can be customized. This is the value used to determine how long must be the time interval of the transition between an existing slide and an entering slide. Both libraries define the same default value of 600ms, a reasonably acceptable value that should be fine for the majority of use cases.

If we want to change this value, given that in both libraries the animation is performed with CSS, first we must add some CSS rules to override the default duration value.

In Bootstrap, we need to use some jQuery code to modify the value hard-coded in the JavaScript:

$carousel.data()['bs.carousel'].constructor.TRANSITION_DURATION = 2000;

Bootstrap Native, on the other hand, exposes a data-duration attribute on the component root element and so the process is easier:

<div id="carousel" class="carousel slide" data-ride="carousel" data-interval="false" data-duration="2000">

An identical option is available for other components (e.g. the Modal and the Tooltip) to change the transition duration.

Other issues are listed and explained on the documentation page and on the project issue tracker.

Conclusion

In my opinion, the project is very interesting, but I would not throw away the original jQuery version so quickly. In fact, as in other ‘jQuery Vs Vanilla JS’ comparisons, the winner often depends on the specific use case.

The issues examined in the previous section should not be major hurdles, so if you are not searching for a perfect literal conversion of the Bootstrap JavaScript components and you are ready to cope with some slight differences, this could be the right solution.

Also, it has to be mentioned that the project is under active development, and fast feedback to issues opened on the GitHub tracker is provided.

So, are you going to give it a try in your next Bootstrap project? Feel free to share your thoughts in the comments.

Login or Create Account to Comment
Login Create Account
Recommended
Sponsors
Get the most important and interesting stories in tech. Straight to your inbox, daily.Is it good?