mixin m-revealer(heading)
	.m-revealer&attributes(attributes)
		.m-revealer__trigger
			h2.m-revealer__heading= heading
			.m-revealer__icon
		.m-revealer__content
			if block
				block
			else
				p Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quippe: habes enim a rhetoribus; Istam voluptatem perpetuam quis potest praestare sapienti? Non enim solum Torquatus dixit quid sentiret, sed etiam cur. Expressa vero in iis aetatibus, quae iam confirmatae sunt. Tamen a proposito, inquam, aberramus. Sed tu istuc dixti bene Latine, parum plane. Duo Reges: constructio interrete. Bonum liberi: misera orbitas. Ut aliquid scire se gaudeant? Quae cum magnifice primo dici viderentur, considerata minus probabantur.

mixin o-accordion(headings)
	.o-accordion
		each heading in headings
			+m-revealer(heading)(class="o-accordion__section")

.o-tabs
	.o-tabs__buttons
		button.o-tabs__button Tab One
		button.o-tabs__button Tab Two
		button.o-tabs__button Tab Three

	.o-tabs__blocks
		.o-tabs__block
			+o-accordion(['One', 'Two', 'Three'])

		.o-tabs__block
			+o-accordion(['Four', 'Five', 'Six'])

		.o-tabs__block
			+o-accordion(['Seven', 'Eight', 'Nine'])
View Compiled
$darkgrey: #1D1F20;

/* o-tabs component file */
.o-tabs {
	max-width: 600px;
	margin: 0 auto;
	
	&__button {
		background: #fff;
		border: 2px solid #000;
		border-bottom: 0;
		padding: 10px 15px;
		font-size: 1.1em;
		
		&:hover {
			background: lightgrey;
			cursor: pointer;
		}
		
		&.-active {
			background: #000;
			color: #fff;

			&:hover {
				background: $darkgrey;
			}
		}
	}
	
	&__blocks {
		border: 1px solid #000;
	}
	
	&__block {
		display: none;
		
		&.-active {
			display: block;
		}
	}
}

/* o-accordion component file */
.o-accordion {
	border-top: 1px solid #000;

	&__section {
		border: 1px solid #000;
		border-top: 0;
	}
}

/* m-revealer component file */
.m-revealer {
	&__trigger {
		display: grid;
		grid-template-columns: 1fr 50px;

		&:hover {
			cursor: pointer;
			background: lightgrey;
		}

// "revealer" now targets a name-spaced
// version of the modifier class instead
		.-revealer--active & {
			background: #000;
			color: #fff;

			&:hover {
				background: $darkgrey;
			}
		}
	}

	&__heading {
		margin: 0;
		padding: 10px 20px;
	}
	
	&__icon {
		position: relative;
		display: flex;
		justify-content: center;
		align-items: center;

		&::before {
			content: '';
			display: block;
			height: 0;
			width: 0;
			border-top: 10px solid #000;
			border-left: 5px solid transparent;
			border-right: 5px solid transparent;

			.-revealer--active & {
				transform: rotate(180deg);
				border-top-color: #fff;	
			}
		}
	}
	
	&__content {
		border-top: 1px solid #000;
		padding: 10px 20px;
		display: none;
		
		.-revealer--active & {
			display: block;
		}
	}
}

/* resets file */
*, *::before, *::after {
	box-sizing: border-box;
}
// revealer.js

class revealer {
	constructor(el){
		Object.assign(this, {
			$wrapper: el,
			isOpen: false,
		});
		this.$trigger = this.$wrapper.querySelector('.m-revealer__trigger');
		this.$trigger.onclick = ()=> this.toggle();
	}
	
	toggle(){
		if (this.isOpen) {
			this.close()
		} else {
			this.open();
		}
	}

	open(){
		this.$wrapper.classList.add(`-revealer--active`);
		this.isOpen = true;
	}

	close(){
		this.$wrapper.classList.remove(`-revealer--active`);
		this.isOpen = false;
	}
}

document.querySelectorAll('.m-revealer').forEach(el => {
	new revealer(el)
})



// tabs.js

class tabs {
	constructor(el){
		Object.assign(this, {
			$wrapper: el,
			isOpen: false,
		});

		this.$triggers = this.$wrapper.querySelectorAll('.o-tabs__button');
		this.$blocks = this.$wrapper.querySelectorAll('.o-tabs__block');

		this.tabs = this.gather_tabs();
		
		this.activate(0);

		this.$triggers.forEach(($trigger, i) => {
			$trigger.onclick = e => {
				e.preventDefault();
				this.activate(i);
			}	
		})
	}

	gather_tabs(){
		const tabs = [];
		this.$triggers.forEach(($trigger, i) => tabs[i] = new tab($trigger, this.$blocks[i]));
		return tabs;
	}

	activate(index){
		this.deactivate_all();
		this.tabs[index].activate();
	}
	
	deactivate_all(){
		this.tabs.forEach(tab => tab.deactivate());
	}
}

class tab {
	constructor($trigger, $block){
		Object.assign(this, {
			$trigger,
			$block,
			isActive: false,
		})
	}
	
	activate(){
		this.$trigger.classList.add('-active');
		this.$block.classList.add('-active');
		this.isActive = true;
	}
	
	deactivate(){
		this.$trigger.classList.remove('-active');
		this.$block.classList.remove('-active');
		this.isActive = false;
	}
}

document.querySelectorAll('.o-tabs').forEach(el => {
	new tabs(el)
})
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.