Read First

Welcome to the demo page! Before you do anything, please make sure to check the Wiki pages, as they give you a quick start with using the library and also provide a good set of valuable guides on how to get the best out of it.

And now, let's get down to business!

Components

Modal

The Modal component works exactly as the original in most regards, with minor exceptions on options, events and public methods. It provides both an initialization option and a public method to write directly into your modal content.

In addition to adapting the spacing (padding) of the <body> elements like <nav class="navbar-fixed-top"> are also adapted in the same manner to get the smoothest possible transition. Like all components of the library, the component has the ability to provide access to the initialization even if your modal is setup via DATA API.

Options

The remote option have been removed in Bootstrap 4 and we already replaced it with a better option. We also skipped the show option because via JavaScript we quickly and easily access the component's public methods right after initialiation, we'll have a look in a minute.

Name type default description
backdrop boolean or the string 'static' true Includes a modal-backdrop element. Alternatively, specify 'static' for a backdrop which doesn't close the modal on click.
keyboard boolean true Option to dismiss the current modal via Esc key.
content markup The Modal component comes with a template system instead of a load remote content function (Bootstrap 4 drops it). This option can be used with JavaScript only.

The default options' values are same as their jQuery plugin equivalents so you can expect same behavior.

Methods

For further control the Modal component exposes a couple of public methods to be used via JavaScript :

.show()

The method that shows an initialized modal. When called, it will also hide any other visible modal before showing the one requested, making sure to keep the backdrop in place.

.hide()

This hides an initialized modal. Additionally it will also close (if enabled) the backdrop.

.toggle()

When called it shows the modal if hidden and hides it otherwise, using the above two methods.

.setContent()

The method to enable you to set/override the content of <div class="modal-content"> element of your modal at any time, but you might want to avoid using this method while the modal is animating.

.update()

This allows you to update the modal layout (handling overflowing/non-overflowing body and/or modal) after you have changed it's content or other layout changes occured. This would naturally follow the previous .setContent() method.

Events

Event Type Description
show.bs.modal This event fires immediately when the .show() instance method is called. If caused by a click and the clicked element is a modal triggering element, that element is available as the event.relatedTarget property of the event.
shown.bs.modal This event is fired when the modal has been made visible to the user. The event.relatedTarget is same as for the above.
hide.bs.modal This event is fired immediately when the .hide() instance method has been called.
hidden.bs.modal This event is fired when the modal has finished being hidden from the user.

The loaded.bs.modal original event is not needed, also because we replaced the remote option with another one. If modal is opened via JavaScript methods, or by clicking on another element that is not a modal triggering element, the relatedTarget is null.

Usage

Via DATA API

You can initialize Modal without writing any code as long as you have a modal and a trigger with data-target or a link with href referencing that modal. The component will initialize for all elements with data-toggle="modal" found in the DOM.

<!-- provide a trigger button -->
<button id="myModalTrigger" type="button" data-toggle="modal" data-target="#myModal">Launch modal</button>

<!-- Alternatively provide a link -->
<a id="myModalTrigger" data-toggle="modal" href="#myModal">Launch modal</a>

<!-- also the modal itself -->
<div id="myModal" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
        Some content
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

The DATA API is suited for static content dialogs.

Via JavaScript

When you write your code, first make sure a modal template is present in the DOM. Generally you can initialize Modal for any instance of <div class="modal"> and immediately get access to methods. Alternativelly you can initialize on a triggering element, similar to how the DATA API works, in this case the data-toggle="modal" is not required, but you need to specify a modal reference via a specific attribute, like so <button data-target="#modalId"> or <a href="#modalId">.

The JavaScript way is the only way to deal with dynamically added modals. Let's create a very basic modal template for the record.

<!-- blank modal template -->
<div id="modalID" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <!-- the .setContent() method will update this element's HTML -->
    </div>
  </div>
</div>

If you are looking for the functionality that grants you full control over your modal without the need of a triggering element, you can initialize that modal and get access to public methods right away:

// get the modal by ID
var myModal = document.getElementById('modalID');

// initialize on a <div class="modal"> with all options
// Note: options object is optional
var myModalInstance = new Modal(myModal, 
{ // options object
  content: '<div class="modal-body">Some content to be set on init</div>', // sets modal content
  backdrop: 'static', // we don't want to dismiss Modal when Modal or backdrop is the click event target
  keyboard: false // we don't want to dismiss Modal on pressing Esc key
});

// OR initialize and show the modal right away
var myModalInstance = new Modal(myModal, options);
myModalInstance.show();
// now you know why we don't need a show option

In other cases you can designate one or multiple triggering elements to open your modal, they will be the target of the constructor initialization and allow you to use same modal as a template to handle contents pushed by the triggering elements.

<!-- <button> referencing the modal -->
<button type="button" id="buttonID" class="btn btn-primary" data-target="#modalID">My Button</button>

<!-- <a> referencing the modal -->
<a id="anchorID" class="btn btn-primary" href="#modalID">My Link</a>

Now let's initialize one of them right away:

// get a certain button trigger
var myButton = document.getElementById('buttonID');

// initiate Modal on a triggering element
var myModalInstance = new Modal(myButton, 
{ // options object
  content: '<div class="modal-body">Some content to be set on init</div>', // sets modal content
  keyboard: false // we don't want to dismiss Modal on pressing Esc key
});

Now we have an initialization reference in myModalInstance, regardless of which element is the target of our constructor, we can start applying the component's public methods.

// show the modal at any time
myModalInstance.show();

// hide the modal
myModalInstance.hide();

// toggle the modal (show/hide)
myModalInstance.toggle();

// change the modal content
myModalInstance.setContent('<div class="modal-body">Some different content</div>');

// if the above method is used while modal was shown, you can then ask for a layout update
myModalInstance.update();

After initialization via DATA API or JavaScript, we also have access to the component's original events.

// GET THE EVENT TARGET, THE MODAL
// when we are certain which modal ID to work with
var myModal = document.getElementById('modalID');

// also button trigger related (especially when modals are targeted by multiple triggering elements) 
// a triggering element is a link
var myModal = document.getElementById(myModalTriggerButton.getAttribute('href').replace('#','')); 
// OR triggering element is not a link
var myModal = document.getElementById(myModalTriggerButton.getAttribute('data-target').replace('#','')); 

// ATTACH HANDLERS
// show.bs.modal event
myModal.addEventListener('show.bs.modal', function(event){
  // do something when this event triggers
  // event.target is the modal referenced in myModal
  // event.relatedTarget is the button referenced with myModalTriggerButton
}, false);

// shown.bs.modal event
myModal.addEventListener('shown.bs.modal', function(event){
  // do something when this event triggers
  // event.target is the modal referenced in myModal
  // event.relatedTarget is the button referenced with myModalTriggerButton
}, false);

// hide.bs.modal event
myModal.addEventListener('hide.bs.modal', function(event){
  // do something when this event triggers
  // event.target is the modal referenced in myModal
}, false);

// hidden.bs.modal event
myModal.addEventListener('hidden.bs.modal', function(event){
  // do something when this event triggers
  // event.target is the modal referenced in myModal
}, false);

Additionally the component will store in the modal and it's triggering elements some references, for the internal execution, hopefully would help you as well. For instance, when a modal is referenced by one or more triggering elements, it will know which one was clicked last time to execute the .show() instance method.

// for modals with multiple triggering elements, the value changes every time the triggering element was clicked
var lastModalTrigger = myModal.modalTrigger;

Also each triggering element holds the initialization of the Modal component:

// when a modal was initialized via DATA API
// OR a triggering element is the target of the Modal constructor
var myModalInstance === document.getElementById('myModalTrigger').Modal; 

These references are used internally to hide currently visible modals when showing another one. When the component is used via JavaScript only without a triggering element, you need to manually hide (via .hide() instance method) any visible modal before showing another modal (via the .show() instance method).

Examples

Using the DATA API

The first example is a modal with static content initialized via DATA API, exactly as described in the above Use via DATA API section, and showcasing the ability to show another modal from a modal currently visible.

Via JavaScript

The following examples are focused on everything the Modal component offers for JavaScript initialization and usage. Given a modal template and some buttons to open the modal on click, let's initialize it first:

// we grab a modal by ID
var myModal = document.getElementById('myModal');

// we grab some button by ID, we will use it later
var btnModal = document.getElementById('openModalViaJS');
// this button IS NOT a triggering element, as it has no reference to the above modal

// set a custom content
var firstModalContent = '<div class="modal-header">'
    +'<button type="button" class="close" data-dismiss="modal" aria-label="Close">'
      +'<span aria-hidden="true">×</span>'
    +'</button>'
    +'<h4 class="modal-title" id="myModalJSLabel">Modal title</h4>'
  +'</div>'
  +'<div class="modal-body">'
    +'<p>This is where you fill up content you know, etc.</p>'
  +'</div>'
  +'<div class="modal-footer">'
    +'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>'
  +'</div>';

// initialize Modal for this triggering element
var modalInitJS = new Modal(myModal, {
  content: firstModalContent,
  backdrop: 'static'
});

// OR initialize with no options provided
// the options obect is optional
var modalInitJS = new Modal(myModal);

// when we click btnModal, open the modal
btnModal.addEventListener('click', function(e){
  modalInitJS.show();
}, false)

Here is what the above code does:

Next we will initialize another triggering button, and attach a handler to it to change content of the modal when clicked.

// the reiggering element
var btnModal2 = document.getElementById('openModalViaJS2');

// set some custom content or get if from external sources
var externalModalContent = {
  title: 'A modal title',
  content: 'Modal content to fill the modal-body.',
};

// set a custom modal-content template
var secondModalContent = 
  '<div class="modal-header">'
    +'<button type="button" class="close" data-dismiss="modal" aria-label="Close">'
      +'<span aria-hidden="true">×</span>'
    +'</button>'
    +'<h4 class="modal-title" id="gridModalLabel">' + externalModalContent.title + '</h4>'
  +'</div>'
  +'<div class="modal-body">'
    +'<p>' + externalModalContent.content + '</p>'
  +'</div>'
  +'<div class="modal-footer">'
    +'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>'
  +'</div>';

// initialize Modal for this triggering element
var modalInitJS2 = new Modal(btnModal2, { backdrop: 'static' });

// now when we click this modal triggering element, we change the modal content
btnModal2.addEventListener('click', function() {
  modalInitJS2.setContent(secondModalContent);
}, false);  

By changing the innerHTML of the modal-header, modal-body or modal-footer with variables, you can achieve exactly the same as the other examples from the demo of the original plugin. So we use same modal, but with different content:

Open Modal

Now if you go back to the previous triggering button and click it, you will notice that the modal is still like it was set by the second triggering button. Let's reset the modal content:

// we grab the button by ID
var btnModalNotTrigger = document.getElementById('modalNotTriggerJS');

// simply attach a click handler to it
btnModalNotTrigger.addEventListener('click', function() {
  modalInitJS.setContent(firstModalContent);  // revert modal content back to previous
  modalInitJS.show(); // also show the modal
}, false);

Back to the previous modal content:

Reset

Another example is using the .update() method. Let's say we have a modal initialized via DATA API, you might think we cannot access this instance's methods. Remember the trigger button stores the initialization?

var modalUpdate = document.getElementById('modalUpdate'), // the trigger
  anotherStaticModal = document.getElementById('anotherStaticModal'), // the modal
  currentStaticModalBody = anotherStaticModal.querySelector('.modal-body'), // the body of the current modal
  currentStaticModalBodyContent = currentStaticModalBody.innerHTML, // we cache the content of the body
  modalUpdateInit = modalUpdate.Modal, // the initialization
  changeModal1 = document.getElementById('changeModal1'), // the change buttons
  changeModal2 = document.getElementById('changeModal2');

changeModal1.addEventListener('click', function(){
  currentStaticModalBody.innerHTML = currentStaticModalBodyContent;
  modalUpdateInit.update();
}, false);

changeModal2.addEventListener('click', function(){
  currentStaticModalBody.innerHTML  = '<h4>This modal changed via JavaScript</h4>';
  currentStaticModalBody.innerHTML += '<p>Something you would want to be displayed in the body.</p>';
  modalUpdateInit.update();
}, false);

A quick demo to showcase the above script:

Show modal

Dropdown

The Dropdown component works like the original jQuery plugin and offers an additional option and an ability to handle click event in a way that you can create nested dropdowns and other cool stuff with ease.

Starting with version 2.0.20 the component supports some more robust accessibility features:

  • Up and Down arrow keys will users to select menu items, and also when pressed, the component will prevent default scroll behavior;
  • Esc key will close the dropdown, a feature previously supported, but reworked it's keyHandler to support the above new features, now it will close the last open nested dropdown element;
  • Enter key will work as if click event triggered, the new event handler expectes the default browser behavior, let's hope it stays that way.

Scrollspy

The ScrollSpy component inherits some of the layout and other requirements from the original jQuery plugin in some cases, while in other cases a special markup is required. The component offers public methods, the specific original event, and can be used with JavaScript as well as via DATA API.

The component will initialize for each element with data-spy="scroll" attribute, but will not work if the above requirements are not met or the anchors don't reference the containers accordingly.

Options

Name type default description
target string
or a
reference
element '#ID'
or other reference
The option to target the container with data-spy="scroll" attribute.
EG: data-target="#myMenuID"
offset number 10 Option to set a number of pixels as offset from top when calculating position of scroll. Can be set via data-offset="NUMBER" attribute or simply offset via JavaScript invokation.

Methods

.refresh()

When DOM layout changes occured without triggering a resize of your element, you will have this option to immediately update the status of your menu items.

Events

Event Type Description
activate.bs.scrollspy This event fires whenever a new item was activated by the component.

The event target is the element we initialized the component via JavaScript or the data-spy="scroll" attribute. The newly activated menu item's link is the event.relatedTarget for the event.

Usage

Via DATA API

To initialize ScrollSpy, remember the requirements from the original jQuery plugin. The component can initialize any element with overflow: auto|scroll and a fixed height, or the <body> or an immediate child element. For the second case we need some special HTML markup in order to initialize and the appropriate styling for its containers.

An overflowing element that has set overflow: auto|scroll style rule:

  • The headings have the required IDs;
  • Only the element requires some additional CSS;
  • No special markup required.
<!-- the element we initialize ScrollSpy on -->
<div data-spy="scroll" data-target="#navbar-example" class="scrollspy-example">

  <!-- we look for the position of heading -->
  <h4 id="one">Title ONE</h4>
  <p>Valid TEXT goes here</p>

  <h4 id="twoOne">Title TWO</h4>
  <p>Valid TEXT goes here</p>

  <h4 id="three">Title THREE</h4>
  <p>Valid TEXT goes here</p>

</div>

<!-- we need a target, any of the below elements with an ID will do -->
<nav id="nav-example"> <!-- we can also target it's parent as well -->
  <ul id="navbar-example" class="nav nav-stacked"> <!-- this is our element's target -->
    <li><a href="#one">One</a></li>
    <li><a href="#two">Two</a></li>
    <li><a href="#three">Three</a></li>
  </ul>
</nav>

In this case we only need to set a fixed height for the element and change its overflow:

/* the element we initialize ScrollSpy on */
.scrollspy-example {
  position: relative; /* required */
  height: 150px; overflow: auto; /* required: height must be px based, and overflow: scroll/auto */
}

A non-overflowing element that wraps most of the content of your page:

  • Special markup IS required;
  • The element's child containers have the required IDs;
  • Child containers require some additional styling.
<!-- the element we initialize ScrollSpy on -->
<div data-spy="scroll" data-target="#navbar-example" class="scrollspy-example">

  <section id="one"> <!-- this is a ScrollSpy container -->
    Valid HTML goes here
  </section>

  <section id="two">
    <section id="twoone">
      One level nested containers also apply
    </section>

    <section id="twotwo">
      This is your second nested container
    </section>
  </section>

</div>

<!-- we need a target, any of the below elements with an ID will do -->
<nav id="nav-example"> <!-- we can also target it's parent as well -->
  <ul id="navbar-example" class="nav nav-stacked"> <!-- this is our element's target -->
    <li><a href="#one">One</a></li>
    <li>
      <a href="#two">Two</a>
      <ul class="nav nav-stacked">
        <li><a href="#twoone">Two One</a></li>
        <li><a href="#twotwo">Two Two</a></li>
      </ul>
    </li>
  </ul>
</nav>

Some additional styling can be used to force ScrollSpy containers to have the exact height as the sum of all child elements and / or child containers.

/* element child containers */
section { 
  position: relative; /* required */
  display: inline-block; width: 100%; /* not required, but recommended */
}

For instances of ScrollSpy when the designated element is not overflowing and the scroll target is the window (like the example with the side navigation of this page), the container nesting is, as you probably noticed, unlimited.

Via JavaScript

For full control and access to the component's features, coding the JavaScript part is a breeze. Assuming the above markup have been injected into the DOM and the CSS is set, let's initialize, apply the public method and attach handlers to the original event.

// the element we initialize ScrollSpy on
var myScrollSpyElement = document.getElementsByClassName('scrollspy-example')[0];

// let's give the initialization a JavaScript reference for the "target" option
var myScrollSpyTarget = document.getElementById('myScrollSpyTarget');

// initialize the ScrollSpy for this element
var myScrollSpyInit = new ScrollSpy(myScrollSpyElement, {
  // set options
  target : myScrollSpyTarget,
  // alternativelly, provide a valid selector string
  // EG: ".my-unique-class-name" or "#my-unique-ID"

  // in some cases the offset option would help calculate 
  // the correct boundaries of target containers
  offset: 15 
})

If the initialization validates (the target option is valid and the component links the element with it's target), we have access to the method and the original event.

// apply the public method after DOM changed
// a new element container and it's corresponding menu item have been injected into the DOM
myScrollSpyInit.refresh();

// attach an event handler
myScrollSpyElement.addEventListener('activate.bs.scrollspy', function(event){
  // do some cool stuff
  // event.target is myScrollSpyElement
  // event.relatedTarget is the menu item link that triggered the event
}, false);

To get access to an initialization object regardless of how it was initialized, here's how to do it:

// grab an element we know it was initialized via DATA API
var myScrollSpy = document.getElementById('myScrollSpy');

// check if the element is already initialized
var myScrollSpyIsInitialized = 'ScrollSpy' in myScrollSpy;

// if the above is true
var myScrollSpyInit = myScrollSpy.ScrollSpy;

// play with the public method
myScrollSpyInit.refresh();

Now this makes alot more sense, especially when you expect full control and also want to make sure you don't attach event handlers multiple times for your elements.

Examples

According to the above Usage Guide let's initialize an overflowing element via DATA API:

Tumblr farm

Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.

Carles aesthetic

Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard. Freegan beard aliqua cupidatat mcsweeney's vero. Cupidatat four loko nisi, ea helvetica nulla carles. Tattooed cosby sweater food truck, mcsweeney's quis non freegan vinyl. Lo-fi wes anderson +1 sartorial. Carles non aesthetic exercitation quis gentrify. Brooklyn adipisicing craft beer vice keytar deserunt.

one

Occaecat commodo aliqua delectus. Fap craft beer deserunt skateboard ea. Lomo bicycle rights adipisicing banh mi, velit ea sunt next level locavore single-origin coffee in magna veniam. High life id vinyl, echo park consequat quis aliquip banh mi pitchfork. Vero VHS est adipisicing. Consectetur nisi DIY minim messenger bag. Cred ex in, sustainable delectus consectetur fanny pack iphone.

two

In incididunt echo park, officia deserunt mcsweeney's proident master cleanse thundercats sapiente veniam. Excepteur VHS elit, proident shoreditch +1 biodiesel laborum craft beer. Single-origin coffee wayfarers irure four loko, cupidatat terry richardson master cleanse. Assumenda you probably haven't heard of them art party fanny pack, tattooed nulla cardigan tempor ad. Proident wolf nesciunt sartorial keffiyeh eu banh mi sustainable. Elit wolf voluptate, lo-fi ea portland before they sold out four loko. Locavore enim nostrud mlkshk brooklyn nesciunt.

three

Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.

Keytar twee blog, culpa messenger bag marfa whatever delectus food truck. Sapiente synth id assumenda. Locavore sed helvetica cliche irony, thundercats you probably haven't heard of them consequat hoodie gluten-free lo-fi fap aliquip. Labore elit placeat before they sold out, terry richardson proident brunch nesciunt quis cosby sweater pariatur keffiyeh ut helvetica artisan. Cardigan craft beer seitan readymade velit. VHS chambray laboris tempor veniam. Anim mollit minim commodo ullamco thundercats.

For this example the overflowing element itself is the target of the scroll event, and above it the .nav component as it's target, while for the other example in this page, the side navigation on the right side, the window is the target of the scroll event.

Tab

The Tab component covers all original jQuery plugin functionality and even comes with new features such as being able to work with any kind of navigation components in Bootstrap, or providing support for height animation as you can see in the example below.

The component can initialize both via JavaScript and the DATA API, covers the original events and exposes a specific public method, but in contrast to the original plugin it offers some options for you to play with.

Options

Name type default description
height boolean false Option to enable animation of the height of the .tab-content tabs container. Can be set via JavaScript or the data-height="true" attribute.

When you set the option to true, this enables a custom functionality that assumes you are using the styling of the Collapse component, and the component animations styling.

Please note that in certain layouts you may need to use the clearfix class for your <div class="tab-content"> element to avoid inconsistent transitions. The option has no effect on legacy browsers.

Methods

.show()

The method to be used to switch to a certain tab of your choice via JavaScript. If that tab is already visible or the method is used while animation is running, the method will produce no effect.

Events

The component events will fire in the exact order shown in table below:

Event Type Description
hide.bs.tab This event fires when a new tab is to be shown (and thus the previous active tab is to be hidden). The event.target is the current active tab, while event.relatedTarget is the new soon-to-be-active tab.
show.bs.tab This event fires on tab show, but before the new tab has been shown. The event.target is the tab next to become active and event.relatedTarget is the current active tab (if available).
hidden.bs.tab This event fires after a new tab is shown (and thus the previous active tab is hidden). The event.target is the tab that just became inactive and event.relatedTarget is the new active tab.
shown.bs.tab This event fires on tab show after a tab has been shown. The event.target is the new active tab and event.relatedTarget is the previous active tab (if available).

Usage

Via DATA API

Here is a sample markup to showcase the usage of the component with the above mentioned methods. As you can see, each of the elements with the data-toggle="tab" attribute are subject to the Tab component initialization.

<!-- for better usage, wrap the tabs and contents -->
<div id="myTabsWrapper">

  <!-- Nav tabs -->
  <ul id="myTabs" class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active">
      <a href="#home" data-toggle="tab" data-height="true" aria-controls="home" role="tab">Home</a>
    </li>
    <li role="presentation">
      <a href="#profile" data-toggle="tab" data-height="true" aria-controls="profile" role="tab">Profile</a>
    </li>
    <li role="presentation">
      <a href="#messages" data-toggle="tab" data-height="true" aria-controls="messages" role="tab">Messages</a>
    </li>
    <li role="presentation">
      <a href="#settings" data-toggle="tab" data-height="true" aria-controls="settings" role="tab">Settings</a>
    </li>
  </ul>

  <!-- Tab panes -->
  <div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="home">...</div>
    <div role="tabpanel" class="tab-pane" id="profile">...</div>
    <div role="tabpanel" class="tab-pane" id="messages">...</div>
    <div role="tabpanel" class="tab-pane" id="settings">...</div>
  </div>

</div>

Also don't forget that this functionality works on CSS3 enabled browsers with the Collapse styling in place.

Via JavaScript

Since the component will target a single element with / or without data-toggle="tab" attribute, but at least it references a corresponding tab via href or data-target, we will need to do a simple loop to initialize multiple elements. Assuming the above markup have been injected into the DOM, let's initialize, use the public method and attach handlers to the original events.

// first, we reference the .nav component that holds all tabs
var myTabs = document.getElementById('myTabs');

// let's give the initialization a JavaScript reference for the "target" option
var myTabsCollection = myTabs.getElementsByTagName('A');

// initialize the component for all items in the collection
for (var i = 0; i < myTabsCollection.length; i++) {
  new Tab(myTabsCollection[i], // our target
  { // our options
    height: true
  });
}

If each item in the collection meets the expected markup and the tab it referencing is found, the initialization will then validate and give you immediate access to method.

// get last item from collection and reference it's initialization
var myLastTab = myTabsCollection[myTabsCollection.length-1];
var myLastTabInit = myLastTab.Tab;

// assuming the last tab is not active, we can show it
myLastTabInit.show();

// attach an event handler as well
myLastTab.addEventListener('show.bs.tab', function(event){
  // do some cool stuff
  // event.target is myLastTab
  // event.relatedTarget is the previous active tab 
}, false);

We could have also built an Object / Array with the initialization objects, but that depends very much on your needs.

Example

OK now we're ready to put this component to the test. We'll use all Bootstrap .nav components in the pool.

Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica.

Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.

Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR.

Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.

Tooltip

Unlike the original jQuery plugin, our Tooltip component will initialize right away all elements with the data-toggle="tooltip" attribute. Additionally the component can do automatic placement without any options required. At half the size of the original plugin, our component here covers most needed options, methods and original events.

Options

The component covers most important options, excluding some of the options featured in the original jQuery plugin such as a template system needed template option, a selector option for auto-initialization, or a trigger option. The component works different but has it's own advantages.

Name type default description
animation string fade Option to customize the component animation. If you are using a different animation other than fade, you can specify that via the data-animation="ANIMATION" attribute. This will add an additional CSS class to the tooltip to enable a custom transition.
placement string top Option to set a specific placement to top, bottom, left or right, relative to it's target. Can be set via both JavaScript and the data-placement="POSITION" attribute.
delay number 200 A short delay before hiding the tooltip. Can be set via JavaScript or the data-delay="DELAY" attribute.
container selector
or object
<body> The container where your tooltips get appended to. You can set the option via JavaScript or the data-container="#elementID" attribute.

If a tooltip is a child element of a modal, a <nav class="navbar-fixed-top"> or a <nav class="navbar-fixed-bottom">, the container option is set automatically to target that specific parent starting with version 2.0.6.

Starting with version 2.0.19, in addition to automatic repositioning, the component will try to make sure the tooltips are always in the viewport as some Popper.js functionality have been implemented into both V3 and V4 versions.

Methods

For full control the Tooltip component exposes a couple of public methods to be used via JavaScript:

.show()

The method shows an initialized tooltip. When the method is executed, it will always create a new tooltip and append it into your desired container.

.hide()

The method hides an initialized tooltip and remove it from it's container and also from the memory, as if you would automatically destroy it.

.toggle()

The method shows the tooltip if hidden and hides it otherwise, using the above two methods.

As you can see we don't use a .destroy() method, the reason for that is explained above, so let's explain how this has it's own advantages: if you change the data-original-title="Your new title" attribute value, next time you mouseover the element, our component will use the new value without having to reinitialize the element. Sweet!

Events

The component's original events are same as with the original jQuery Plugin, except inserted.bs.tooltip, the way the component works makes that this event is not needed, as it would fire on every instance of the .show() method.

Event Type Description
show.bs.tooltip This event fires immediately when the show instance method is called.
shown.bs.tooltip This event is fired when the tooltip has been made visible to the user.
hide.bs.tooltip This event is fired immediately when the hide instance method has been called.
hidden.bs.tooltip This event is fired when the tooltip has finished being hidden from the user.

Usage

Via DATA API

As mentioned before the component will initialize any element found to have the data-toggle="tooltip" attribute and a title attribute or a data-title attribute for SVG elements.

<!-- any regular link with data-toggle="tooltip" -->
<a href="https://google.com" title="Google" data-toggle="tooltip">Google</a>

<!-- any SVG shape with data-toggle="tooltip" -->
<svg viewBox="0 0 80 34" width="80" height="34" xmlns="http://www.w3.org/2000/svg">
  <rect data-toggle="tooltip" data-placement="top" data-delay="150" data-title="Demo Title for SVG" rx="5"></rect>
</svg>
Via JavaScript

When you insert new items in the page and want them to initialize the component or you want to have full control over your tooltips, the JavaScript way is the best one. You can also initialize for elements not having the specific DATA API, but at least have a title="Not null title" attribute. You can do the following:

// find all elements with title attribute
var elementsTooltip = document.querySelectorAll('[title]');

// attach a tooltip for each
for (var i = 0; i < elementsTooltip.length; i++){
  new Tooltip(elementsTooltip[i], {
    placement: 'top', //string
    animation: 'slideNfade', // CSS class
    delay: 150, // integer
  })
}

In addition, similar to any other component of this library, you can access the initialization and the public methods even for elements initialized via DATA API.

// find an element initialized with Tooltip
var myLinkWithTooltip = document.getElementById('myLinkWithTooltip');

// reference the initialization object
var myTooltipInit = myLinkWithTooltip.Tooltip;

Considering the just above element, let's go ahead and put the component's events to use:

// show.bs.tooltip
myLinkWithTooltip.addEventListener('show.bs.tooltip', function(event){
  // do some cool stuff when .show() method is called
  // event.target is myLinkWithTooltip
}, false);

// shown.bs.tooltip
myLinkWithTooltip.addEventListener('shown.bs.tooltip', function(event){
  // do some cool stuff when .show() method completed
  // event.target is myLinkWithTooltip
}, false);

// hide.bs.tooltip
myLinkWithTooltip.addEventListener('hide.bs.tooltip', function(event){
  // do some cool stuff when .hide() method is called
  // event.target is myLinkWithTooltip
}, false);

// hidden.bs.tooltip
myLinkWithTooltip.addEventListener('hidden.bs.tooltip', function(event){
  // do some cool stuff when .hide() method completed
  // event.target is myLinkWithTooltip
}, false);

Examples

Now let's test all the other placement positions, we start with inline links having the bottom placement, then left, and right. Let's put it to the test! Some heavy testing on the automatic repositioning with very very long tooltips.

SVG

Popover

Similar to the above, the Popover component will initialize all elements with the data-toggle="popover" attribute. Unlike the original jQuery plugin, this component does not require the Tooltip component and works just about the same as the above except that Popover has the ability to work with templates and trigger options.

Options

The component covers all needed options, including those for a template system:

Name type default description
template markup Option to use a custom HTML template via JavaScript only for your popovers. See examples below for info.
content markup Option to set the content of the popover via JavaScript or the data-content="CONTENT" attribute.
title markup Option to set the title of the popover via JavaScript or the data-title="TITLE" attribute.
dismissible boolean false Option to option to make the popover dismissible. When true, it will also add an X button at the top-right of the popover. You can enable this option via data-dismissible="true" attribute.
trigger string hover Option to change the component's action trigger event: hover, focus and click. In some cases you may want to open a popover on focus for form elements or click for other buttons, you can specify that via JavaScript or the data-trigger="EVENT" attribute.
animation string fade Option to customize the component animation. If you are using a different animation other than fade, you can specify that via the data-animation="ANIMATION" attribute. This will add an additional CSS class to the popover to enable a custom transition.
placement string top Option to set a specific placement to top, bottom, left or right, relative to it's target. Can be set via both JavaScript and the data-placement="POSITION" attribute.
delay number 200 A short delay before hiding the popover.
Can be set via JavaScript or the data-delay="DELAY" attribute.
container selector
or object
<body> The container where your popovers get appended to. You can set the option via JavaScript or the data-container="#elementID" attribute.

If a popover is a child element of a modal, a <nav class="navbar-fixed-top"> or a <nav class="navbar-fixed-bottom"> element, the container option is set automatically to target that specific parent starting with version 2.0.6.

If a proper template is not specified via JavaScript or the content option is not set in any way, the Popover will not be initialized.

Starting with version 2.0.19, in addition to automatic repositioning, the component will try to make sure the popovers are always in the viewport as some Popper.js functionality have been implemented into both V3 and V4 versions.

Methods

For full control the Popover component exposes a couple of public methods to be used via JavaScript:

.show()

The method shows an initialized popover. When the method is executed, it will always create a new popover and append it into your desired container.

.hide()

The method hides an initialized popover and remove it from it's container and also from the memory, as if you would automatically destroy it.

.toggle()

The method shows the popover if hidden and hides it otherwise, using the above two methods.

Also like the Tooltip component, there's no need for a .destroy() method, for the same reason for that is explained before.

Events

The component's original events are same as with the original jQuery Plugin, except inserted.bs.popover, just as explained for the Tooltip component.

Event Type Description
show.bs.popover This event fires immediately when the show instance method is called.
shown.bs.popover This event is fired when the popover has been made visible to the user.
hide.bs.popover This event is fired immediately when the hide instance method has been called.
hidden.bs.popover This event is fired when the popover has finished being hidden from the user.

Usage

Via DATA API

So out component will initialize any element found to have the data-toggle="popover" attribute and a data-content attribute.

<!-- any regular link with data-toggle="popover" -->
<a href="https://google.com" data-title="Google" data-content="Google is cool" data-toggle="popover">Google</a>

<!-- any SVG shape with data-toggle="popover" -->
<svg viewBox="0 0 80 34" width="80" height="34" xmlns="http://www.w3.org/2000/svg">
  <rect data-toggle="popover" data-placement="top" data-delay="150" data-content="Demo Title for SVG" rx="5"></rect>
</svg>
Via JavaScript

After inserting new content into the page, you can initialize any element with Popover via JavaScript. You can also initialize for elements not having the specific DATA API. You can do the following:

// find all elements with data-content attribute
var elementsPopover = document.querySelectorAll('[data-content]'); // also a certain class would go fine

// attach a popover for each
for (var i = 0; i < elementsPopover.length; i++){
  new Popover(elementsPopover[i], {
    placement: 'top', //string
    animation: 'slideNfade', // CSS class
    delay: 100, // integer
    dismissible: true, // boolean
  })
}

In addition, similar to any other component of this library, you can access the initialization and the public methods even for elements initialized via DATA API.

// find an element initialized with Popover
var myLinkWithPopover = document.getElementById('myLinkWithPopover');

// reference the initialization object
var myPopoverInit = myLinkWithPopover.Popover;

Considering the just above element, let's go ahead and put the component's events to use:

// show.bs.popover
myLinkWithPopover.addEventListener('show.bs.popover', function(event){
  // do some cool stuff when .show() method is called
  // event.target is myLinkWithPopover
}, false);

// shown.bs.popover
myLinkWithPopover.addEventListener('shown.bs.popover', function(event){
  // do some cool stuff when .show() method completed
  // event.target is myLinkWithPopover
}, false);

// hide.bs.popover
myLinkWithPopover.addEventListener('hide.bs.popover', function(event){
  // do some cool stuff when .hide() method is called
  // event.target is myLinkWithPopover
}, false);

// hidden.bs.popover
myLinkWithPopover.addEventListener('hidden.bs.popover', function(event){
  // do some cool stuff when .hide() method completed
  // event.target is myLinkWithPopover
}, false);

To use the template system, you can do the following:

//define some variables or get their values from other scripts
var someTitleFromOtherCode = 'Sample title';
var someContentFromOuterSpace = '<p>Some sample message.</p>';

//initiate Popover with the template
var popover2 = new Popover('.popover-via-template', { // where .popover-via-template is the text input
  trigger: 'focus',
  template: '<div class="popover" role="tooltip">'
  + '<div class="arrow"></div>'
  + '<h3 class="popover-title">'+someTitleFromOtherCode+'</h3>'
  + '<div class="popover-content">'+someContentFromOuterSpace+'</div>'
  + '</div>'
});

Examples

First let's test all the placement positions, we start with inline links having the bottom placement, then left, and right.

Now we are going to test buttons with a popover with large contents. The last two examples below are using the template system and different trigger options. The popover generated for the last two examples can be dismissed on window resize or blur (focus out).

SVG

Alert

The Alert component covers the specific original event and public method, but does not provide any option. Still, the component will initialize both via JavaScript or the DATA API. In contrast with the original plugin is the fact that the component does not require the class alert-dismissible in order to work.

Options

This component has no options.

Methods

The Alert component exposes a single public method to be used via JavaScript:

.close()

The method hides an initialized alert and remove it from DOM.

Events

The component's original events are same as with the original jQuery Plugin.

Event Type Description
close.bs.alert This event is fired immediately when the close instance method has been called.
closed.bs.alert This event is fired when the alert has finished being hidden from the user.

Usage

Via DATA API

The component will initialize all elements with proper DATA API found in the DOM. Note that the data-dismiss="alert" attribute is required for the triggering button.

<!-- notice the <button> with the data-dismiss="alert" attribute -->
<div id="myWarningAlert" class="alert alert-warning alert-dismissible fade in" role="alert">
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">×</span>
  </button>
  Some critical notice. 
</div>
Via JavaScript

After inserting a new alert into the page, you can initialize it via JavaScript. Considering the above markup, you can do the following:

// find all elements with data-content attribute
var myWarningAlert = document.getElementById('myWarningAlert');

// initialize
var myWarningAlertInit = new Alert(myWarningAlert);

Also attach handlers to the original events:

// close.bs.alert
myWarningAlert.addEventListener('close.bs.alert', function(event){
  // do something cool
  // event.target is <div class="alert">
}, false);

// closed.bs.alert
myWarningAlert.addEventListener('closed.bs.alert', function(event){
  // do something cool
  // event.target is <div class="alert">
}, false);

Like all components of the library you can access the initialization object even if it was done via the DATA API:

// find an element initialized via DATA API
var myAlertButton = document.getElementById('myAlertButton');

// reference the initialization object
var myAlertInit = myAlertButton.Alert;

// apply the public method
myAlertInit.close();

Examples

This alert has some handlers attached to close.bs.alert and closed.bs.alert events, so check your console.

This alert uses the closed.bs.alert event to show another alert.

Button

The Button component provides text/stateful switch and toggle checkboxes and radio buttons for button groups. The component provides a custom event for the button groups' toggling, not covered by the original jQuery Plugin.

Button doesn't cover single toggle feature. The supported toggle feature could very much fill the same purpose.

Options

Name type default description
option string The only option is for the component's stateful switch. Can be used only in a combination of the data-OPTION-text="Button text" attribute and a JavaScript call.

Methods

The Button component exposes no public methods.

Events

Unlike the original jQuery Plugin, the Button component comes with an original event, consistent in all supported browsers.

Event Type Description
change.bs.button The event is fired for a .btn-group and each child .btn that changed it's checked state.

Usage

Stateful Switching

The component will help you call for text switching on button elements with proper DATA API, but you have to manually call via JavaScript. This feature doesn't require the data-toggle="button" attribute, only one or more data-OPTION-text="Your text" attribute(s), so let's consider a button for instance:

<!-- a basic markup for the button -->
<button type="button" id="myButton" data-loading-text="Loading..." class="btn btn-primary">
  Loading state
</button>

Now this button markup is using the specific DATA API but it won't do anything by itself unless you call it via JavaScript. There always has to be an action to call the change of the button's state such as event handlers:

// grab the above .btn element
var btn = document.getElementById('myButton');

// let's say we call the switch on click
btn.addEventListener('click', function() {
  Button(btn,'loading'); 
});
// this assumes Button is using "loading" as an option from the data-loading-text="Loading..." attribute

When the button is clicked, it will change its text and because loading is a special option, the component will add a disabled CSS class to the button and a new data-original-text="Loading State" attribute.

To reset the button to it's original state, we have to do the same thing but use a different option, so let's say we need to hook into an instance of XMLHttpRequest, here's what you do:

// create a new instance of XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.google.com');

// bind into the context of the readyStateChange event
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4)  {
    // do something specific when complete
    // here we call the Button state change
    Button(btn,'reset');
  }
};
xhr.send();

When the reset option is used, the component will look for the data-original-text attribute and use its value for the button's text. In addition, if the button was made disabled via the loading option, it will remove the disabled="disabled" attribute and the disabled CSS class, to fully restore the element to it's original state.

After the use of the loading option, we could have used data-original-text and Button(btn,'original'); but it woulnd't have the same effect as the reset option. It would simply update the text but not the other option's disabled CSS class and attribute.

Radios / Checkboxes Toggling

This function applies to radio buttons and checkboxes that use the special .btn-group Bootstrap component's markup:

 <!-- the btn-group component -->
<div id="myCheckboxesButtonGroup" class="btn-group" data-toggle="buttons">
  <label class="btn btn-default active">
    <input type="checkbox" autocomplete="off" checked> Checkbox 1 (pre-checked) <!-- OR type="radio" -->
  </label>
  <label class="btn btn-default">
    <input type="checkbox" autocomplete="off"> Checkbox 2 <!-- OR type="radio" -->
  </label>
  <label class="btn btn-default">
    <input type="checkbox" autocomplete="off"> Checkbox 3 <!-- OR type="radio" -->
  </label>
</div>

If the above markup is present in the DOM when the library is loaded, it will initialize via DATA API, if inserted later into the DOM, here's how to initialize it:

// find the element to apply Button to
var myCheckboxesButtonGroup = document.getElementById('myCheckboxesButtonGroup');

// initialize
var myCheckboxesButtonGroupINIT = new Button(myCheckboxesButtonGroup);

If the component finds the markup to meet all requirements, it will initialize it and the myCheckboxesButtonGroup element will store the initialization, just like the other components of the library:

// reference the initialization, even for DATA API initialized btn-group elements
var myCheckboxesButtonGroupInit = myCheckboxesButtonGroup.Button;

The only thing left to do is to attach handlers to the original events:

//let's do some custom binding action
myCheckboxesButtonGroup.addEventListener('change.bs.button', function(event) {
  // do something when anything inside the btn-group changes
  // event.target is myCheckboxesButtonGroup
});
myCheckboxesButtonGroup.getElementsByTagName('INPUT')[0].addEventListener('change.bs.button',function(event) {
  // do something only when THE FIRST input changes
  // event.target is the first <input type="checkbox"> found in myCheckboxesButtonGroup
});

Since the native change event isn't consistent in legacy browsers, with the help of polyfills and the original change.bs.button event you can easily bind other functions into the context of a .btn-group and / or it's child inputs.

Examples

Stateful Switching

Here is a quick example of button state switch just like the original plugin example, we use the loading state for the button. For the purpose of testing here, the button will come back to original state after a short setTimeout delay and the usage of reset option.

Radios / Checkboxes Toggling

You should open your console to test the handler functions bound by the change.bs.button event of the following checkboxes and radio buttons. You should notice that the event isn't triggered twice and it works properly with IE8+.

First we'll toggle some checkboxes.

Finally we toggle radio buttons.

In addition, the component will also work outside the <div class="btn-group">.

Collapse

The Collapse component covers the original events and methods of the jQuery plugin counterpart. This component understands there is a triggering element that finds its target collapsible element via the data-target="#collapse-id" attribute or the href="#collapse-id" attribute if it's a link.

Options

The option below allow you to connect a collapse to a parent accordion.

Name type default description
parent selector
or
reference
Option to reference a parent to be used as an accordion. When a parent is set and found, it will enable the functionality described in the show() method below. Can be set via JavaScript or the data-parent="SELECTOR" attribute.

Methods

Calling any of the public methods while animation is running, will produce no effect.

.show()

The method will expand a collapsible element. In addition, if the collapsible element is part of an accordion (it's options include a reference to a parent), it will also close any other visible collapsible element.

.hide()

The method hides a collapsible element.

.toggle()

The method will show / or hide a collapsible element using the above methods and their full functionalities.

Events

All the component's events are attached to the collapsible element and not its targeting button / element, with other words, the event.target is the element with the class="collapse" attribute.

Event Type Description
show.bs.collapse This event fires immediately when the show instance method is called.
shown.bs.collapse This event is fired when a collapse element has been made visible to the user.
hide.bs.collapse This event is fired immediately when the hide method has been called.
hidden.bs.collapse This event is fired when a collapse element has been hidden from the user.

Usage

Via DATA API

In the following markup, the component will initialize on the two .btn.btn-primary elements with the data-toggle="collapse", both targeting the same collapsible element with specific atttributes.

<!-- toggle collapse via link with HREF reference -->
<a id="collapseLink" class="btn btn-primary" role="button" aria-expanded="false" aria-controls="collapseExample"
  data-toggle="collapse" href="#collapseExample"> <!-- required DATA API -->
  Link with href
</a>

<!-- AND / OR toggle collapse via button with data-target attribute reference -->
<button id="collapseButton" class="btn btn-primary" type="button" aria-expanded="false" aria-controls="collapseExample"
  data-toggle="collapse" data-target="#collapseExample"> <!-- required DATA API -->
  Button with data-target
</button>

<!-- and the basic collapsible template -->
<div class="collapse" id="collapseExample">
  <div class="well">
    ...
  </div>
</div>

Now if we stack multiple collapsible elements and wrap them into one parent with an ID attribute and some helper CSS classes, we can easily create an accordion.

<!-- accordion template -->
<div class="panel-group" id="myAccordion" role="tablist" aria-multiselectable="true">
  <div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingOne">
      <h4 class="panel-title">
        <a role="button" data-toggle="collapse" data-parent="#myAccordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
          Collapsible Group Item #1
        </a>
      </h4>
    </div>
    <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
      <div class="panel-body">
        Collapse CONTENT 1
      </div>
    </div>
  </div>
  <div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingTwo">
      <h4 class="panel-title">
        <a class="collapsed" role="button" data-toggle="collapse" data-parent="#myAccordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
          Collapsible Group Item #2
        </a>
      </h4>
    </div>
    <div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">
      <div class="panel-body">
        Collapse CONTENT 2
      </div>
    </div>
  </div>
  <div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingThree">
      <h4 class="panel-title">
        <a class="collapsed" role="button" data-toggle="collapse" data-parent="#myAccordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
          Collapsible Group Item #3
        </a>
      </h4>
    </div>
    <div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
      <div class="panel-body">
        Collapse CONTENT 3
      </div>
    </div>
  </div>
</div>
Via JavaScript

If the above single collapse template have been inserted into the DOM, you need to initialize it via JavaScript.

// grab the accordion by its ID
var collapseLink = document.getElementById('collapseLink');

// initialize the component for this collapse trigger
var myCollapseInit = new Collapse(collapseLink)

This now enables you to work with the public methods.

// call the show() right away
myCollapseInit.show();

// call the hide() later
// myCollapseInit.hide();

// OR call toggle() some other time 
// myCollapseInit.toggle();

Also we can attach some handlers to the original events:

// first, we need to reference the collapsible element
var myCollapseExample = document.getElementById(collapseLink.getAttribute('href').replace('#',''));

// attach a handler to the `show.bs.collapse` original event
myCollapseExample.addEventListener('show.bs.collapse', function(event){
  // do something cool when .show() method is called
  // event.target is myCollapseExample
}, false);

Alright, now let's say the above accordion template have been inserted into the DOM, you need to initialize its collapsible elements right away via JavaScript.

// grab the accordion by its ID
var myAccordion = document.getElementById('myAccordion');

// grab the collapsible triggers for this accordion
var myAccordionTriggers = myAccordion.querySelectorAll('[data-toggle="collapse"]');

// initialize the component for each collapse trigger
for (var i = 0; i < myAccordionTriggers.length; i++){
  new Collapse(myAccordionTriggers[i], {
    parent: myAccordion // this is the above defined object
  });
}

The component grants access to the initialization even for instances where the DATA API was used.

// grab the collapse trigger initialized via DATA API
var myCollapseTrigger = document.getElementById('myCollapseTrigger');

// reference the initialization
var myCollapseTriggerInit = myCollapseTrigger.Collapse;

Examples

Single collapsible element

Here's a quick demo with a single collapsible element, using the .well as the container, exactly as described in the Usage section. The demo also features the original events.

HREF

Accordion / multiple collapsible elements

Here's an Accordion example, built with a set of Panels wrapped in a <div class="panel-group"> element. When the toggle links are clicked, our Collapse component will look for the closest <div class="accordion-className"> or <div id="accordion-id"> via data-parent="selector" and will hide any visible collapsible element.

Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.

Remember that all triggering buttons must reference the accordion via data-parent="selector" as described above in order to collapse current opened collapsible element.

Carousel

The Carousel component covers the original events, along with a set of useful options and public methods. In addition it also provides a solid DATA API, it adds a paused class to the targeted element when in paused state, and a solid event handling implementation.

Options

Name type default description
keyboard boolean true Option that allows yout to navigate the carousel with left and right arrows.
pause boolean
or
the text 'hover'
'hover' Option that makes possible to pause the carousel transition on mouse hover and touchdown. If you want to disable pause on hover, do that via JavaScript or the data-pause="false" attribute.
interval number 5000 Option the component's delay between transitions in miliseconds. Can be set via JavaScript or the data-interval="INTERVAL" attribute. If you want to disable the automatic transition, you can set this option to false. Starting with version 2.0.19 the component will not automatically slide if the element is not visible in the viewport.

Methods

.cycle()

The method will cycle through items. Using the method while the animation is running will produce no effect.

.slideTo()

The method will allow you to jump to the index of a certain item. Using the method while the animation is running will produce no effect.

.getActiveIndex()

The method returns the index of the current active item.

Events

All the component's events are attached to the <div class="carousel"> element, and the event.relatedTarget is the newly activated carousel item. The events provide no mention of the animation direction, because most polyfills do not allow us to set new custom properties to the event objects, we store the transition direction in the initialization object. See the Usage section.

Event Type Description
slide.bs.carousel This event fires immediately when the slideTo() instance method is called.
slid.bs.carousel This event is fired when transition has finished.

Usage

Via DATA API

The component covers most of the original implementation in regards to DATA API, except that you can ignore data-slide="prev" and data-slide="next" attributes for the controls, but they must have at least the class carousel-control in order to work. The elements with the data-ride="carousel" attribute will be initialized via DATA API, and the basic template looks like this:

<!-- the Carousel component -->
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="5000">
  <!-- Indicators -->
  <ol class="carousel-indicators">
    <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
    <li data-target="#myCarousel" data-slide-to="1"></li>
    <li data-target="#myCarousel" data-slide-to="2"></li>
  </ol>
  <!-- Wrapper for slides -->
  <div class="carousel-inner" role="listbox">
    <div class="item active">
      <img src="https://unsplash.it/837/300?image=0" alt="">
      <div class="carousel-caption">
      <h3>This is another carousel</h3>
      </div>
    </div>
    <div class="item">
      <img src="https://unsplash.it/837/300?image=10" alt="">
      <div class="carousel-caption">
      <h3>This is a caption</h3>
      </div>
    </div>
    <div class="item">
      <img src="https://unsplash.it/837/300?image=210" alt="">
      <div class="carousel-caption">
      <h3>This is another caption</h3>
      </div>
    </div>
  </div>

  <!-- Controls -->
  <a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
    <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
    <span class="sr-only">Previous</span>
  </a>
  <a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
    <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
    <span class="sr-only">Next</span>
  </a>
</div>

A quick walk through the attributes:

  • id="myCarousel" is required only if you inject the above template into the DOM and need a way to target this specific element, unlike the original jQuery plugin that requires this attribute for the its internal event handlers;
  • data-ride="carousel" makes the element targetable by the Carousel component;
  • data-interval="5000" sets the automatic slide interval;
  • data-slide-to="0" when clicked, will slide to the carousel item with that index, 0 (zero) in this case;
  • data-slide="prev" / data-slide="next" when clicked, will slide to the next / previous carousel item; these attributes are optional, but the class carousel-control is required;
  • class="item active" / class="active" when active is present for an item or indicator, that indicates which carousel item is currently shown to the user, the above .getActiveIndex() method will look for it when needed.
Via JavaScript

The component grants full access to the internal working via JavaScript; whether via the public methods or the original events, you can do a whole bunch of things. Assuming the above markup have been injected into the DOM, let's go ahead and initialize it:

// grab the carousel element
var myCarousel = document.getElementById('myCarousel');

// initialize with some options
var myCarouselInit = new Carousel(myCarousel, { // these options values will override the ones set via DATA API 
  interval: false,
  pause: false,
  keyboard: false
});

And now we can play with the methods:

// use getActiveIndex()
var currentActiveItem = myCarouselInit.getActiveIndex();

// jump to a certain item
myCarouselInit.slideTo(2);

// if the carousel was set with `interval: false`
// we can do this to go to the next item
myCarouselInit.cycle();

As you probably expect by now, this component also stores the initialization in the element it targets on initialization, even for instances where the DATA API was used:

// get some carousel item and reference the initialization
var mySpecialCarouselInit = document.getElementById('mySpecialCarousel').Carousel;

// apply methods
mySpecialCarouselInit.cycle();

And now, instead of just writing some code sample on how to use the events, let's actually explain how the carousel at the top of this page works. With the help of the original events and some CSS, let's animate the contents of the items:

// grab the myCarousel on top of the page
var mainSlider = document.getElementById('myCarousel');

// also reference its items in an array
var mainSliderItems = mainSlider.querySelectorAll('.item');

// use the `slide.bs.carousel` event to remove the `slide` class
// FROM the div.carousel-caption of the newly activated item
mainSlider.addEventListener('slide.bs.carousel', function(e) {
  // the Carousel compoenent also stores initialization in the targeted element object
  var currentActiveIndex = mainSlider.Carousel.getActiveIndex(); 
  var activeCaption = mainSliderItems[currentActiveIndex].querySelector('.carousel-caption');
  activeCaption.classList.remove('slide');
});

// use the `slid.bs.carousel` event to add the `slide` class 
// TO the div.carousel-caption of the newly activated item
mainSlider.addEventListener('slid.bs.carousel', function(e) {
  // e.relatedTarget is the newly activated item
  var activeCaption = e.relatedTarget.querySelector('.carousel-caption'); 
  activeCaption.classList.add('slide');
});

To determine the slide direction, we simply access the initialization:

// read direction set by the last transition 
var slideDirection = mainSlider.Carousel.direction;

// read it when `slide.bs.carousel` is triggered
mainSlider.addEventListener('slide.bs.carousel', function(e) {
  slideDirection = mainSlider.Carousel.direction;

  // now do something you need with slideDirection before transition
});

// read it when `slid.bs.carousel` is triggered
mainSlider.addEventListener('slid.bs.carousel', function(e) {
  slideDirection = mainSlider.Carousel.direction;

  // now do something you need with slideDirection after transition
});

Example

This is a test demonstrating the component capabilities and it's events, so open your console, and start clicking, you will be noticed before and after the animation. Also know that there was no active item set by default in the markup, proving the component can successfully manage this case by setting the first item as active on initialization.

Jump

Affix

The Affix component has it's own options and public method, but covers all the original events of the jQuery plugin. It inherits the same basic functionality as well as the CSS requirements to make it all work properly.

Options

Name type default description
target selector
or
reference
Option to pin an element to top once the scroll reaches it's target offsetTop. You can set the target via data-target=".target-className" or data-target="#target-ID" attribute.
offsetTop number
or
function
Option to pin an element to top when scroll reaches a specific value. This can be set via the data-offset-top="OFFSET" attribute, or via JavaScript you can assign a number or a function to the offsetTop option.
offsetBottom number
or
function
Option to pin an element to bottom at a certain offset relative to the window maximum scroll. This can be set via the data-offset-bottom="OFFSET" attribute, or via JavaScript you can assign a number or a function to the offsetBottom option.

Using static values for offsetTop and / or offsetBottom would work best on non-responsive websites, or when the elements don't change their height when window resize occurs.

Methods

.update()

When DOM layout changes occured without triggering a resize in your context, you will have this option to immediately update the affix status of your element.

Events

Event Type Description
affix.bs.affix This event fires immediately before the element has been affixed.
affixed.bs.affix This event is fired after the element has been affixed.
affix-top.bs.affix This event fires immediately before the element has been affixed-top.
affixed-top.bs.affix This event is fired after the element has been affixed-top.
affix-bottom.bs.affix This event fires immediately before the element has been affixed-bottom.
affixed-bottom.bs.affix This event is fired after the element has been affixed-bottom.

Usage

Required CSS

First we need to make sure our element is properly styled to make sure it works properly. For instance this is the style we needed for the navigation on the right side to make it work:

/* this style applies to mobile devices, on screens SMALLER than 768px */
#side-nav {clear: both}
#side-nav .nav.affix,
#side-nav .nav.affix-bottom { position: relative; margin: 20px 0; } /* relative position recommended */

/* this style applies to other devices, on screens LARGER than 768px */
@media (min-width: 768px) {
  #side-nav .nav.affix, /* the fixed position and a width are required */
  #side-nav .nav.affix-bottom { position: fixed !important; width: 263px; }
  #side-nav .nav.affix { top: 0; }  /* affixedTop position */
  #side-nav .nav.affix-bottom { top: auto; bottom: 100px; }  /* affixedBottom position */
}

In addition, via JavaScript you can ask the browser to update the value of width: 263px; on window resize.

Via DATA API

Alright, we put the styling out of the way, we'll have a look at our example here on this very page. So we configure an element to be pinned to top targeting a certain element's position and a bottom offset of around 120px.

<ul id="myAffix" class="nav nav-stacked" data-spy="affix" data-target="#use" data-offset-bottom="120">
  <!-- menu items -->
</ul>

If everything is set properly you should be able to achieve the same exact effect.

Via JavaScript

Assuming the above element has been injected into the page, you can initialize it via JavaScript:

// grab the element by it's ID
var myAffix = document.getElementById('myAffix');

// initialize
var theAffixInit = new Affix(myAffix, {
  target: '#use',
  offsetBottom: 120,
});

// use the public method any time you see fit
theAffixInit.update();

Also via JavaScript we can set offset options as functions:

// grab the element by it's ID
var myAffix = document.getElementById('myAffix');

// initialize with some cool options
var theAffixInit = new Affix(myAffix, {
  offsetTop: function() {
    var rectTop = document.getElementById('use').getBoundingClientRect().top;
    var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    return rectTop + scrollTop;
  },
  offsetBottom: function() {
    var reasonableMargin = 20;
    var elementHeight = myAffix.offsetHeight;
    var footerHeight = document.getElementsByTagName('footer')[0].offsetHeight;
    var maxScroll = Math.max( 
        document.body.scrollHeight, 
        document.body.offsetHeight, 
        document.documentElemnt.clientHeight, 
        document.documentElement.scrollHeight, 
        document.documentElement.offsetHeight );
    return maxScroll - elementHeight - footerHeight - reasonableMargin;
  },
});

Now let's make use of some of the component's original events:

// affix.bs.affix
myAffix.addEventListener('affix.bs.affix', function(event){
  // do something when myAffix is about to be affixed top or bottom
  // event.target is myAffix
}, false);

// affixed-top.bs.affix
myAffix.addEventListener('affixed-top.bs.affix', function(event){
  // do something when myAffix is affixed top
  // event.target is myAffix
}, false);

// and so on

If your element have been initialized by the component via DATA API, you can still access the initialization object:

// grab the element by it's ID
var myAffix = document.getElementById('myAffix');

// reference the initialization
var theAffixInit = myAffix.Affix;

// use the public method
theAffixInit.update();

Example

We don't have a working example for this component in this section, due to the complexity and requirements, however the navigation on the right side of this page is a good example, it covers initialization via DATA API, the required styling and the original events.