recital / core / example / js / tabs.js
tabs.js
Raw
/**
 * Creates scaffolding for tabs.
 * Requires a format similar to:
 *
 * <div class="tab-links">
 * 	<button data-tab="one">Tab 1</button>
 * 	<button data-tab="two">Tab 2</button>
 * </div>
 * <div class="tab-contents">
 * 	<div id="one">
 * 		Tab contents for button 1
 * 	</div>
 * <div id="two">
 * 		Tab contents for button 2
 * 	</div>
 * </div>
 *
 * Where the links have a `data-tab` property, and the contents
 * have an id that matches those properties. They must be immediate
 * children of the parent containers.
 * @param {HTMLElement} tabLinks - container for the tab buttons
 * @param {HTMLElement} tabContents - container for the tab contents
 * @param {string} defaultTab - optional - id for the tab that should be visible by default. Otherwise, defaults to the first tab
 */
function createTabs(tabLinks, tabContents, defaultTab) {
	const children = tabLinks.children
	for (let child of children) {
		if (child.tagName.toLowerCase() === 'button') {
			if (!defaultTab) {
				defaultTab = child.dataset.tab
			}
			// add a function
			child.onclick = () => {
				hideAllTabContents(tabContents)
				setActiveTabLink(tabLinks, child.dataset.tab)
				showTab(tabContents, child.dataset.tab)
			}
		}
	}

	hideAllTabContents(tabContents)
	showTab(tabContents, defaultTab)
	setActiveTabLink(tabLinks, defaultTab)
}

function hideAllTabContents(tabContents) {
	for (let tabContent of tabContents.children) {
		tabContent.style.display = 'none'
	}
}

function showTab(tabContents, tabId) {
	let tab = tabContents.querySelector('#' + tabId)
	if (!tab) {
		console.warn('Trying to show nonexistent tab')
		return
	}
	tab.style.display = 'block'
}

function setActiveTabLink(tabLinks, activeTabId) {
	for (let tabLink of tabLinks.children) {
		tabLink.className = tabLink.className.replace(' active', '')
		if (tabLink.dataset.tab === activeTabId) {
			tabLink.className += ' active'
		}
	}
}