Global Elements
2
Footer Header Services Strip Services Tabs
Components
36
Card Carousel Cards Grid Content Overlap Content Strip Cta Bar Featured Article Featured Blocks Featured Expert Featured Pods Featured Tabs Form Block Full Screen Carousel Full Width Content Heading Strip Hero Hero Featured Links List Location Tabs Logo Carousel Map Block People Grid Quote Block Reviews Carousel Reviews Tabs Service Tiles Services Strip Services Tabs Staggered Content Sticky Accordion Sticky List Sub Navigation Team Carousel Team Filters Team Strip Tile Carousel Tile Grid

Featured Tabs

Field
Field Type
Field Name
Instructions
Block Data
tab
Tabs
repeater
tabs
-- Tab Title
text
tab_title
-- Heading Type
select
heading_type
-- Heading Text
text
heading_text
-- Copy
wysiwyg
copy
-- Buttons
repeater
buttons_list
---- Button
link
button
-- Background Image
image
background_img
Block Meta
tab
ID
text
block_id
Block Classes
text
block_classes
Block Theme
select
block_theme
Background Colors
select
background_colors
Padding Top
select
padding_top
Padding Bottom
select
padding_bottom
Margin Top
select
margin_top
Margin Bottom
select
margin_bottom

				
@import "../../resources/scss/util/colours";
@import "../../resources/scss/util/variables";
@import "../../resources/scss/util/mixins";

.block-featured-tabs {
	width: 100%;
	background-color: $lightBlue;

	&__background-images {
		position: absolute;
		top: 0;
		right: 0;
		width: 100%;
		height: 100vh;
		opacity: 0.2;
		display: none;

		@include bp($lg) {
			display: block;
		}
	}

	&__background-image {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-position: center;
		opacity: 0;
		transition: all 0.3s ease-in-out;

		&.active {
			opacity: 1;
		}
	}

	&__list-background {
		background-color: $lightBlue;
		height: 100%;
		justify-content: flex-end;
		display: none;
		height: calc(100vh - 141px);
		position: absolute;
		top: 0;
		left: 0;
		right: 0;

		@include bp($lg) {
			display: flex;
		}
	}

	&__content-background {
		background-color: $navy;
		height: 100%;
		display: flex;
		flex-direction: column;
		justify-content: center;
	}

	&__copy {
		color: $white;

		a {
			color: $white;
			transition: all 0.3s ease-in-out;

			&:hover {
				color: $orange;
			}
		}
	}

	&__tab-heading {
		color: $white;
		font-family: $font-family-heading;
		@include fluid-type(24, 32);
		margin-bottom: rem-calc(24);
	}

	&__tab-content {
		width: rem-calc(580);
		max-width: 100%;
		padding-left: rem-calc(20);
		padding-right: rem-calc(20);
		padding-top: rem-calc(30);
		padding-bottom: rem-calc(30);
		height: auto;
		display: flex;
		flex-direction: column;
		justify-content: center;
		position: relative;
		z-index: 9;

		@include bp($lg) {
			height: calc(100vh - 141px);
			padding-left: rem-calc(100);
			padding-right: rem-calc(20);
			padding-top: rem-calc(20);
			padding-bottom: rem-calc(20);
		}
	}

	&__tabs-container {
		width: rem-calc(580);
		display: none;
		flex-direction: column;
		height: 100%;
		justify-content: center;

		@include bp($lg) {
			display: flex;
		}
	}

	&__tab-link {
		color: $darkBlue;
		font-family: $font-family-heading;
		@include fluid-type(24, 40);
		opacity: 0.2;
		transition: all 0.3s ease-in-out;
		position: relative;
		margin-bottom: rem-calc(56);
		display: block;

		a {
			text-decoration: none;
			color: $darkBlue;
			display: block;
		}

		&:last-of-type {
			margin-bottom: 0;
		}

		&:after {
			content: '';
			position: absolute;
			bottom: 0;
			left: 0;
			right: 0;
			width: 0;
			height: rem-calc(1);
			background-color: $darkBlue;
			transition: all 0.7s ease-in-out;
		}

		&:hover {
			opacity: 1;

			&:after {
				width: 100%;
			}
		}

		&.active {
			opacity: 1;

			&:after {
				width: 100%;
			}
		}
	}

	&.is-active {
		.block-featured-tabs__list-background {
			position: fixed;
			top: rem-calc(141);
			left: 0;
			width: 50%;
			bottom: auto;
		}

		.block-featured-tabs__background-images {
			position: fixed;
			top: rem-calc(141);
			width: 50%;
			right: 0;
		}
	}

	&.leave {
		.block-featured-tabs__list-background {
			position: absolute;
			left: 0;
			width: 100%;
			top: auto;
			bottom: 0;
		}

		.block-featured-tabs__background-images {
			position: absolute;
			top: auto;
			width: 100%;
			right: 0;
			bottom: 0;
		}
	}
}
class FeaturedTabs {
	/**
	 * Create and initialise objects of this class
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor
	 * @param {object} block
	 */
	constructor() {
		this.blocks = document.querySelectorAll('.block-featured-tabs');
		this.init();
	}

	/**
	 * Example function to run class logic
	 * Can access `this.block`
	 */
	init() {
		this.blocks.forEach((block) => {

			const pinCarousel = ScrollTrigger.matchMedia({
				"(min-width: 992px)": function() {
					ScrollTrigger.create({
						id: 'pinCarousel',
						trigger: block,
						pin: false,
						pinSpacing: false,
						start: "top 141px",
						end: "bottom bottom",
						toggleClass: {targets: block, className: "is-active"},
						onEnter: () => {
							block.classList.remove('leave');
							block.classList.add('is-active');
						},
						onEnterBack: () => {
							block.classList.remove('leave');
							block.classList.add('is-active');
						},
						onLeave: () => {
							block.classList.remove('is-active');
							block.classList.add('leave');
						},
						onLeaveBack: () => {
							block.classList.remove('is-active');
							block.classList.remove('leave');
						}
					});
				},
			});

			$(document).ready(function() {
				if(window.location.hash.length > 0) {
					window.scrollTo(0, $(window.location.hash).offset().top);
				}
			});


			const tabConntents = block.querySelectorAll(".block-featured-tabs__tab-content");
			const tabLinks = block.querySelectorAll(".block-featured-tabs__tab-link");
			const tabImages = block.querySelectorAll(".block-featured-tabs__background-image");

			const updateActiveLinks = (tab, image) => {
				tabLinks.forEach((link) => {
					link.classList.remove("active");
				});
				tab.classList.add("active");

				tabImages.forEach((image) => {
					image.classList.remove("active");
				});
				image.classList.add("active");
			}

			// tabLinks.forEach((link) => {
			// 	link.addEventListener("click", () => {
			// 		document.getElementById("divFirst").scrollIntoView();
			// 	})
			// })

			if (tabConntents) {
				tabConntents.forEach((content) => {

					let tabID = content.getAttribute("data-section");
					let tabLink = block.querySelector(`[data-id="${tabID}"]`);
					let tabImage = block.querySelector(`[data-image="${tabID}"]`);

					ScrollTrigger.matchMedia({
						"(min-width: 992px)": function() {
							ScrollTrigger.create({
								trigger: content,
								start: "top 50%",
								end: "bottom bottom",
								onEnter: () => {
									updateActiveLinks(tabLink, tabImage);
								},
								onEnterBack: () => {
									updateActiveLinks(tabLink, tabImage);
								},
								onLeave: () => {
									updateActiveLinks(tabLink, tabImage);
								},
								onLeaveBack: () => {
									updateActiveLinks(tabLink, tabImage);
								}
							});
						},
					});
				});
			}

			ScrollTrigger.matchMedia({
				"(min-width: 992px)": function() {
					ScrollTrigger.create({
						id: 'pinCarousel',
						trigger: block,
						pin: false,
						pinSpacing: false,
						start: "top 141px",
						end: "bottom bottom",
						toggleClass: {targets: block, className: "is-active"},
						onEnter: () => {
							block.classList.remove('leave');
							block.classList.add('is-active');
						},
						onEnterBack: () => {
							block.classList.remove('leave');
							block.classList.add('is-active');
						},
						onLeave: () => {
							block.classList.remove('is-active');
							block.classList.add('leave');
						},
						onLeaveBack: () => {
							block.classList.remove('is-active');
							block.classList.remove('leave');
						}
					});
				},
			});

		});
	}
}

new FeaturedTabs();
This component is not currently used on any pages.

Animation / States

  • The minimum height of this component will be 100vh of the users viewport. If the content is longer then the height pods themselves will become scrollable
  • As the user scrolls this component will become fixed to the top of the viewport as the user scrolls through the tabs highlighted on the left
  • As the user scrolls the tabs will fade in/out to reveal the next tab on the left which will reveal the content assigned to the tab on the right
  • The tabs on the left will be clickable to navigate through the various tabs

External Libraries

  • Swiper
  • ScrollTrigger (GSAP)

Notes (Design / Dev / SEO)

No notes.