<div class="hero-carousel h-margin-bottom-2" data-carousel-delay="7000">
<h1 class="h-visibility-hidden">This is the hero carousel heading!</h1>
<div class="hero-carousel__media swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<figure>
<img src="/mocks/img/hero-carousel.jpg" srcset="/mocks/img/hero-carousel.jpg 375w, /mocks/img/hero-carousel.jpg 750w, /mocks/img/hero-carousel.jpg 1430w, /mocks/img/hero-carousel.jpg 2860w" alt="#" />
</figure>
</div>
<div class="swiper-slide">
<figure>
<img src="/mocks/img/hero-carousel-2.jpg" srcset="/mocks/img/hero-carousel-2.jpg 375w, /mocks/img/hero-carousel-2.jpg 750w, /mocks/img/hero-carousel-2.jpg 1430w, /mocks/img/hero-carousel-2.jpg 2860w" alt="#" />
</figure>
</div>
<div class="swiper-slide">
<figure>
<img src="/mocks/img/hero-carousel-3.jpg" srcset="/mocks/img/hero-carousel-3.jpg 375w, /mocks/img/hero-carousel-3.jpg 750w, /mocks/img/hero-carousel-3.jpg 1430w, /mocks/img/hero-carousel-3.jpg 2860w" alt="#" />
</figure>
</div>
<div class="swiper-slide">
<figure>
<img src="/mocks/img/hero-carousel-4.jpg" srcset="/mocks/img/hero-carousel-4.jpg 375w, /mocks/img/hero-carousel-4.jpg 750w, /mocks/img/hero-carousel-4.jpg 1430w, /mocks/img/hero-carousel-4.jpg 2860w" alt="#" />
</figure>
</div>
</div>
<div class="hero-carousel__navigation">
<ul>
<li>
<button data-index="0">
<span>Vill du snabbt få förslag på rätt ventilation?</span>
</button>
</li>
<li>
<button data-index="1">
<span class="hero-carousel__label">Ny produkt</span>
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</button>
</li>
<li>
<button data-index="2">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</button>
</li>
<li>
<button data-index="3">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</button>
</li>
</ul>
</div>
</div>
<div class="hero-carousel__content">
<div class="hero-carousel__content-item">
<h2>Vill du snabbt få förslag på rätt ventilation?</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#" class="button">Primary</a>
</div>
<div class="hero-carousel__content-item">
<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#" class="button">Primary</a>
</div>
<div class="hero-carousel__content-item">
<h2>Consectetur adipiscing elit.</h2>
<p>Consectetur adipiscing elit.</p>
</div>
<div class="hero-carousel__content-item">
<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#" class="button">Primary</a>
</div>
</div>
<div class="hero-carousel__options">
<button class="hero-carousel__toggle-autoplay">
<svg class="icon hero-carousel_play-button" focusable="false">
<use xlink:href="#icon-play"></use>
</svg>
<svg class="icon hero-carousel_pause-button" focusable="false">
<use xlink:href="#icon-pause"></use>
</svg>
</button>
</div>
</div>
<div class="hero-carousel h-margin-bottom-2" data-carousel-delay="{{delay}}">
{{#if heading}}<h1 class="h-visibility-hidden">{{heading}}</h1>{{/if}}
<div class="hero-carousel__media swiper-container">
<div class="swiper-wrapper">
{{#each items}}
{{#with image}}
<div class="swiper-slide">
<figure>
<img
src="{{src}}"
srcset="{{src}} 375w, {{src2x}} 750w, {{src2x}} 1430w, {{src2x}} 2860w"
alt="{{alt}}"
/>
</figure>
</div>
{{/with}}
{{/each}}
</div>
<div class="hero-carousel__navigation">
<ul>
{{#each items}}
{{#with navigation}}
<li>
<button data-index="{{@index}}">
{{#if label}}<span class="hero-carousel__label">{{label}}</span>{{/if}}
<span>{{text}}</span>
</button>
</li>
{{/with}}
{{/each}}
</ul>
</div>
</div>
<div class="hero-carousel__content">
{{#each items}}
<div class="hero-carousel__content-item">
{{#with content}}
<h2>{{title}}</h2>
{{#if body}}<p>{{body}}</p>{{/if}}
{{#if button}}
<a
href="{{button.link}}"
class="button"
>{{button.label}}</a>
{{/if}}
{{/with}}
</div>
{{/each}}
</div>
<div class="hero-carousel__options">
<button class="hero-carousel__toggle-autoplay">
{{> @icon id="play" additionalClasses="hero-carousel_play-button"}}
{{> @icon id="pause" additionalClasses="hero-carousel_pause-button"}}
</button>
</div>
</div>
{
"heading": "This is the hero carousel heading!",
"delay": 7000,
"items": [
{
"content": {
"title": "Vill du snabbt få förslag på rätt ventilation?",
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"button": {
"label": "Primary",
"link": "#"
}
},
"image": {
"src": "/mocks/img/hero-carousel.jpg",
"src2x": "/mocks/img/hero-carousel.jpg",
"alt": "#"
},
"navigation": {
"text": "Vill du snabbt få förslag på rätt ventilation?"
}
},
{
"content": {
"title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"button": {
"label": "Primary",
"link": "#"
}
},
"image": {
"src": "/mocks/img/hero-carousel-2.jpg",
"src2x": "/mocks/img/hero-carousel-2.jpg",
"alt": "#"
},
"navigation": {
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"label": "Ny produkt"
}
},
{
"content": {
"title": "Consectetur adipiscing elit.",
"body": "Consectetur adipiscing elit."
},
"image": {
"src": "/mocks/img/hero-carousel-3.jpg",
"src2x": "/mocks/img/hero-carousel-3.jpg",
"alt": "#"
},
"navigation": {
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
}
},
{
"image": {
"src": "/mocks/img/hero-carousel-4.jpg",
"src2x": "/mocks/img/hero-carousel-4.jpg",
"alt": "#"
},
"content": {
"title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"button": {
"label": "Primary",
"link": "#"
}
},
"navigation": {
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
}
}
]
}
import Swiper from 'swiper';
export default function HeroCarousel(el) {
const swiperContainer = el.querySelector('.swiper-container');
const navButtons = el.querySelectorAll('.hero-carousel__navigation button');
const contentItems = el.querySelectorAll('.hero-carousel__content-item');
const autoplayButton = el.querySelector('.hero-carousel__toggle-autoplay');
const delay = el.getAttribute('data-carousel-delay') || 7000;
autoplayButton.classList.add('is-playing');
const swiper = new Swiper(swiperContainer, {
loop: true,
slidesPerView: 1,
autoplay: {
delay: delay,
disableOnInteraction: true
},
on: {
slideChange: function () {
const index = swiper.realIndex;
updateContent(index);
updateNavigation(index);
// Handle play/pause state if autoplay is not running after slideChange and drag event.
if (!swiper.autoplay.running) {
autoplayButton.classList.remove('is-playing');
}
}
}
});
function updateContent(nextIndex) {
const currentIndex = [...contentItems].findIndex((item) =>
item.classList.contains('active')
);
const currentItem = contentItems[currentIndex];
const nextItem = contentItems[nextIndex];
if (!nextItem) return;
contentItems.forEach((item) => item.classList.remove('fade-out'));
if (currentItem && currentIndex !== nextIndex) {
currentItem.classList.remove('active');
requestAnimationFrame(() => {
currentItem.classList.add('fade-out');
});
setTimeout(() => {
currentItem.classList.remove('fade-out');
nextItem.classList.add('active');
}, 500);
} else {
contentItems.forEach((el, i) => {
el.classList.toggle('active', i === nextIndex);
});
}
}
function updateNavigation(index) {
const scrollEl = el.querySelector('.hero-carousel__navigation ul');
navButtons.forEach((btn, i) => {
const isActive = i === index;
btn.classList.toggle('active', isActive);
if (isActive && scrollEl.scrollWidth > scrollEl.clientWidth) {
const item = btn.parentElement;
let scrollLeft;
if (i === navButtons.length - 1) {
scrollLeft = scrollEl.scrollWidth - scrollEl.clientWidth;
} else {
scrollLeft = item.offsetLeft;
}
scrollEl.scrollTo({
left: scrollLeft,
behavior: 'smooth'
});
}
});
}
navButtons.forEach((button) => {
button.addEventListener('mousedown', (e) => e.stopPropagation());
button.addEventListener('touchstart', (e) => e.stopPropagation());
button.addEventListener('click', () => {
const index = parseInt(button.dataset.index, 10);
swiper.slideToLoop(index);
swiper.autoplay.stop();
autoplayButton.classList.remove('is-playing');
updateNavigation(index);
});
});
autoplayButton.addEventListener('click', () => {
if (swiper.autoplay.running) {
swiper.autoplay.stop();
autoplayButton.classList.remove('is-playing');
} else {
swiper.autoplay.start();
autoplayButton.classList.add('is-playing');
}
});
/* Observer Purpose
- Pause auto play when scrolled beyond Image carousel
*/
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
swiper.autoplay.stop();
autoplayButton.classList.remove('is-playing');
}
});
},
{
threshold: 0
}
);
observer.observe(swiperContainer);
// Init
updateContent(swiper.realIndex);
updateNavigation(swiper.realIndex);
}
.hero-carousel {
display: flex;
flex-direction: column;
position: relative;
.swiper-slide {
width: 100%;
text-align: center;
height: auto;
display: flex;
align-items: center;
justify-content: center;
}
.button {
margin: 0;
}
}
// Image Carousel
.hero-carousel__media {
width: 100%;
overflow: hidden;
figure {
position: relative;
width: 100%;
margin: 0;
padding-bottom: 100%;
@include breakpoint($m) {
height: 570px;
padding-bottom: 0;
}
}
img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
left: 0;
}
&:before {
content: " ";
position: absolute;
width: 600px;
height: 100%;
background: linear-gradient(
90deg,
rgba(0, 0, 0, 0.4) 0%,
rgba(0, 0, 0, 0) 100%
);
z-index: 2;
}
&:after {
content: " ";
display: block;
bottom: 0;
left: 0;
right: 0;
position: absolute;
width: 100%;
height: 85px;
background: linear-gradient(
0,
rgba(0, 0, 0, 0.4) 0%,
rgba(0, 0, 0, 0) 100%
);
z-index: 1;
}
}
.hero-carousel__content,
.hero-carousel__navigation {
width: 100%;
}
// Content
.hero-carousel__content {
background-color: $color-white;
padding: 20px 12px 0;
@include breakpoint($m) {
background-color: transparent;
position: absolute;
top: 60px;
left: 32px;
padding: 0;
z-index: 1;
max-width: 540px;
width: 70%;
h2,
p {
color: $color-white;
}
}
}
.hero-carousel__content-item {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s ease,
transform 0.5s cubic-bezier(0.69, 0.24, 0.03, 0.87);
position: absolute;
top: 0;
left: 0;
width: 100%;
pointer-events: none;
}
.hero-carousel__content-item.active {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
position: relative;
z-index: 1;
}
.hero-carousel__content-item.fade-out {
position: relative;
opacity: 0;
transform: translateY(-20px);
pointer-events: none;
z-index: 0;
}
// Navigation
.hero-carousel__navigation {
position: absolute;
bottom: 0;
z-index: 2;
ul,
li {
margin: 0;
padding: 0;
list-style: none;
color: $color-white;
}
ul {
display: flex;
flex-direction: row;
overflow-x: auto;
padding-bottom: 16px;
padding-right: 8px;
white-space: nowrap;
}
li {
display: flex;
align-items: flex-end;
flex: 0 0 200px;
text-align: left;
padding-left: 8px;
&:first-child {
padding-left: 16px;
}
@include breakpoint(0, 440px) {
flex: 0 0 100%;
max-width: 60%;
}
@include breakpoint(560px, $s) {
flex: 0 0 calc(33% - 8px);
}
}
button {
display: flex;
width: 100%;
justify-content: flex-end;
flex-direction: column;
text-align: left;
cursor: pointer;
border-bottom: 2px solid rgba($color-white, 0.4);
padding-bottom: 2px;
font-weight: 700;
&.active {
border-bottom: 4px solid $color-white;
padding-bottom: 0;
}
span:not(.hero-carousel__label) {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.hero-carousel__label {
margin-right: auto;
background: $color-green-pale;
color: $color-green;
text-transform: uppercase;
font-size: 12px;
line-height: 20px;
padding: 0 4px;
}
}
}
// Play and pause
.hero-carousel__options {
position: absolute;
top: 16px;
right: 16px;
z-index: 1;
svg {
fill: $color-white;
width: 36px;
height: 36px;
}
}
.hero-carousel_play-button,
.hero-carousel_pause-button {
display: none;
cursor: pointer;
}
.hero-carousel__toggle-autoplay.is-playing .hero-carousel_pause-button {
display: inline-block;
}
.hero-carousel__toggle-autoplay:not(.is-playing) .hero-carousel_play-button {
display: inline-block;
}
import HeroCarousel from './HeroCarousel';
const els = document.querySelectorAll('.hero-carousel');
for (let el of els) {
HeroCarousel(el);
}
No notes defined.