Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Include the link to the JS component and instantiate like this:
</script>
```

You can also use `window.tabs` to create a Reponsive Tabs instance.

To initialize it, make sure you run the `init` method:

```javascript
Expand All @@ -48,6 +50,66 @@ To go to a specific tab index manually after instantiation, you can use the `goT
myTabs.goToTab(3);
```

## Advanced usage

### Using custom element

You can also pass an already existing element as an option:

```javascript
var tabsContainer = document.querySelector('#tabs');

var myTabs = window.tabs({
el: tabsContainer,
tabNavigationLinks: '.c-tabs-nav__link',
tabContentContainers: '.c-tab'
});
```

### Multiple instances

Using previous example enables the option to create multiple Responsive Tabs instances of same class on the same page:

```javascript
document.querySelectorAll('.c-tabs').forEach(function (el) {
var myTabs = window.tabs({
el: el,
tabNavigationLinks: '.tab',
tabContentContainers: '.tab-content'
});
myTabs.init();
});
```

### Custom classes for active elements

You can also define your own classes for active tab links and contents to match the desired CSS syntax.

Renaming default `is-active` class using `activeClass` option:

```javascript
var myTabs = tabs({
el: '#tabs',
tabNavigationLinks: '.c-tabs-nav__link',
tabContentContainers: '.c-tab',

activeClass: 'c-tab--active'
});
```

Assigning different classes for tab links and tab contents using `activeClassLink` and `activeClassContainer` options:

```javascript
var myTabs = tabs({
el: '#tabs',
tabNavigationLinks: '.c-tabs-nav__link',
tabContentContainers: '.c-tab',

activeClassLink: 'c-tabs-nav__link--active',
activeClassContainer: 'c-tab--active'
});
```

## No JS Fallback

Some simple CSS is provided for a no-js solution. If JS is enabled, the `no-js` class gets removed during instantiation and all works well!
Expand Down
167 changes: 97 additions & 70 deletions js/src/tabs.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,111 @@
(function() {

'use strict';

/**
* tabs
*
* @description The Tabs component.
* @param {Object} options The options hash
*/
var tabs = function(options) {

var el = document.querySelector(options.el);
var tabNavigationLinks = el.querySelectorAll(options.tabNavigationLinks);
var tabContentContainers = el.querySelectorAll(options.tabContentContainers);
var activeIndex = 0;
var initCalled = false;
'use strict';

/**
* init
* tabs
*
* @description Initializes the component by removing the no-js class from
* the component, and attaching event listeners to each of the nav items.
* Returns nothing.
* @description The Tabs component.
* @param {Object} options The options hash
*/
var init = function() {
if (!initCalled) {
initCalled = true;
el.classList.remove('no-js');

for (var i = 0; i < tabNavigationLinks.length; i++) {
var link = tabNavigationLinks[i];
handleClick(link, i);
var tabs = function(options) {

var el = options.hasOwnProperty('el') ? parseElement(options.el) : false;
if (el === false) {
console.error('[Responsive Tabs] Option "el" is not defined');
return;
}
}
};
else if (!el) {
console.error('[Responsive Tabs] Failed to find an element of selector:', options.el);
return;
}
var tabNavigationLinks = el.querySelectorAll(options.tabNavigationLinks);
var tabContentContainers = el.querySelectorAll(options.tabContentContainers);
var activeClass = options.hasOwnProperty('activeClass') ? options.activeClass : 'is-active';
var activeClassLink = options.hasOwnProperty('activeClassLink') ? options.activeClassLink : activeClass;
var activeClassContainer = options.hasOwnProperty('activeClassContainer') ? options.activeClassContainer : activeClass;
var activeIndex = 0;
var initCalled = false;

/**
* handleClick
*
* @description Handles click event listeners on each of the links in the
* tab navigation. Returns nothing.
* @param {HTMLElement} link The link to listen for events on
* @param {Number} index The index of that link
*/
var handleClick = function(link, index) {
link.addEventListener('click', function(e) {
e.preventDefault();
goToTab(index);
});
};
/**
* init
*
* @description Initializes the component by removing the no-js class from
* the component, and attaching event listeners to each of the nav items.
* Returns nothing.
*/
var init = function() {
if (!initCalled) {
initCalled = true;
el.classList.remove('no-js');

for (var i = 0; i < tabNavigationLinks.length; i++) {
var link = tabNavigationLinks[i];
handleClick(link, i);
}
}
};

/**
* parseElement
*
* @description Parses option that can be of different types
* @param el {Element|string}
* @returns {Element}
*/
function parseElement(el) {
if (el instanceof Element) {
return el;
}
else if (typeof el === 'string') {
return document.querySelector(el);
}
}

/**
* handleClick
*
* @description Handles click event listeners on each of the links in the
* tab navigation. Returns nothing.
* @param {HTMLElement} link The link to listen for events on
* @param {Number} index The index of that link
*/
var handleClick = function(link, index) {
link.addEventListener('click', function(e) {
e.preventDefault();
goToTab(index);
});
};

/**
* goToTab
*
* @description Goes to a specific tab based on index. Returns nothing.
* @param {Number} index The index of the tab to go to
*/
var goToTab = function(index) {
if (index !== activeIndex && index >= 0 && index <= tabNavigationLinks.length) {
tabNavigationLinks[activeIndex].classList.remove(activeClassLink);
tabNavigationLinks[index].classList.add(activeClassLink);
tabContentContainers[activeIndex].classList.remove(activeClassContainer);
tabContentContainers[index].classList.add(activeClassContainer);
activeIndex = index;
}
};

/**
* Returns init and goToTab
*/
return {
init: init,
goToTab: goToTab
};

/**
* goToTab
*
* @description Goes to a specific tab based on index. Returns nothing.
* @param {Number} index The index of the tab to go to
*/
var goToTab = function(index) {
if (index !== activeIndex && index >= 0 && index <= tabNavigationLinks.length) {
tabNavigationLinks[activeIndex].classList.remove('is-active');
tabNavigationLinks[index].classList.add('is-active');
tabContentContainers[activeIndex].classList.remove('is-active');
tabContentContainers[index].classList.add('is-active');
activeIndex = index;
}
};

/**
* Returns init and goToTab
* Attach to global namespace
*/
return {
init: init,
goToTab: goToTab
};

};

/**
* Attach to global namespace
*/
window.tabs = tabs;
window.tabs = tabs;

})();
})();