how to conditionally style links in Nuxt/Vue - html

I'm building a Nuxt app and am having trouble with conditional styling. What I'm trying to do is apply a different background color to the active link depending on what page it is. I know I can use .nuxt-link-exact-active to style the active link, but I'm stuck on how to make that different on each page.
I have the links in a component that gets rendered on each page. I've tried using .nuxt-link-exact-active at the page level, but it doesn't get picked up.
Here's what I've got so far, which does change the styling depending on the page, but it does it for all the links, and I only want it on the active link. Please let me know if I can clarify anything. Thanks!
<template>
<nav class="flex-container flex-column mt-1">
<NuxtLink to="/about" class="link" :class="classObject">about</NuxtLink>
<div class="mt-1 flex-container">
<NuxtLink to="/projects" class="link" :class="classObject"
>projects</NuxtLink
>
</div>
<div class="mt-1 flex-container">
<NuxtLink to="/contact" class="link" :class="classObject"
>contact</NuxtLink
>
</div>
</nav>
</template>
<script>
export default {
// apply current route name as a class to the matching div
computed: {
classObject() {
return {
about: this.$route.name === 'about',
projects: this.$route.name === 'projects',
contact: this.$route.name === 'contact',
}
},
},
}
</script>
<style lang="scss" scoped>
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>
illustration of what I'm trying to do

Instead of changing .nuxt-link-exact-active at the page level, change it in the layout.
So for example, in layouts/default.vue:
<style>
.nuxt-link-exact-active {
background: red;
}
</style>

I came up with a solution— not sure if it's the best way, but it works. Each link is now preceded by a div that only gets rendered on the corresponding page, otherwise a link is rendered.
<template>
<nav class="flex-container flex-column mt-1">
<div v-if="currentPageName === 'about'" class="box about">
<h2>about</h2>
</div>
<div v-else>
<NuxtLink to="/about" class="link">about</NuxtLink>
</div>
<div v-if="currentPageName === 'projects'" class="box projects">
<h2>projects</h2>
</div>
<div v-else>
<NuxtLink to="/projects" class="link">projects</NuxtLink>
</div>
<div v-if="currentPageName === 'contact'" class="box contact">
<h2>contact</h2>
</div>
<div v-else>
<NuxtLink to="/contact" class="link">contact</NuxtLink>
</div>
</nav>
</template>
<script>
export default {
computed: {
currentPageName() {
return this.$route.name
},
},
}
</script>
<style lang="scss" scoped>
.box {
width: 150px;
height: 150px;
}
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>

I think the easiest way to check if the path is active or not is $nuxt.$route.path.
<template>
<ul>
<li>
<nuxt-link :to="links[0].path" :class="{'bg-black text-white': links[0].path == path }">{{ links[0].name }}</nuxt-link>
<nuxt-link :to="links[1].path" :class="{secondStyle: links[1].path == path }">{{ links[1].name }}</nuxt-link>
</li>
</ul>
</template>
<script>
export default {
name: "Header",
data() {
return {
path: null,
links: [
{path: "/link1", name: "Link 1"},
{path: "/link2", name: "Link 2"}
],
};
},
mounted() {
this.path = $nuxt.$route.path;
},
};
</script>

Related

Display FontAwesome icon in Vue 3 with JavaScript array

I am trying to display FontAwesomeicon
<font-awesome-icon icon="fa-solid fa-shop" />
with JavaScript array to be dynamic but it's not working it displays as text
<div class="aboutme-card" v-for="(item,index) in servicesArr" :key="index">
<div class="service-card-icon">{{item.icon}}</div> <!--but its display as text not as icon svg-->
<div class="service-card-title">{{item.title}}</div>
<p class="service-card-desc">{{item.description}}</p>
</div>
<script>
export default {
data() {
return {
servicesArr: [
{
icon: `<font-awesome-icon icon="fa-solid fa-shop" />`,
title: "E-commerce",
}
]
}
}
}
</script>
Isn't something like this conceivable in your case?
<template>
<div class="aboutme-card" v-for="item in servicesArr" :key="item.icon">
<div class="service-card-icon">
<font-awesome-icon :icon="item.icon" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
servicesArr: [
{
icon: "fa-solid fa-shop",
title: "E-commerce",
}
]
}
}
}
</script>
Even if v-html exists, it's usually not the way to go.
Especially in such a simple use-case where dynamic props are totally fine.
Overall, I still recommend that solution for overall ease of use + flexibility.

VUE: How to multiple component partials in one file?

home.vue
<template>
<app-navbar>
<logo title="navbar"></logo>
<div class="navbar-collapse">
<link href="#first" title="first link"></link>
<link href="#second" title="second link"></link>
<link href="#third" title="third link"></link>
</div>
</app-navbar>
</template>
<script>
export default {
name: "Home",
components: {
AppNavbar: () => import('#/components/navbar.vue')
}
}
</script>
navbar.vue
<script>
export default {
name: "AppNavbar",
props: {
title: {
type: String,
default: "navbarDemo"
},
href: {
type: String,
default: "#"
}
},
template: `
<div class="navbar-container">
<component :is="logo">
<div class="navbar-brand">{{ title }}</div>
</component>
<ul>
<component :is="link">
<li class="item">
<a :href="href" class="link">{{ title }}</a>
</li>
</component
</ul>
</div>
</div>
`
};
</script>
I WANT THIS
<div class="navbar-container">
<div class="navbar-brand">navbar</div>
<div class="navbar-collapse">
<ul>
<li class="item">
first link
</li>
<li class="item">
second link
</li>
<li class="item">
third link
</li>
</ul>
</div>
</div>
What am I doing wrong? Is component used differently? I want to use a component and have another component in it in one file (I don't want to have 20 files here just for navbar). Then compose the structure in this way. Possible?
I'm trying a similar HTML structure as here: link
Here is what you need:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<a :href="link.href">{{ link.title }}</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
The logo element is passed through a slot (https://fr.vuejs.org/v2/guide/components-slots.html).
You understood <component> wrongly :p <component> do not declare a component, it's only a way to use a component when its name might change.
Instead of writing
<comp1 v-if="test" /> <comp2 v-else /> you could write <component :is="test ? 'comp1" : 'comp2' />. But comp1 and comp2 components still need to be declared somewhere and imported.
Did you check https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components ?
EDIT: If you want to customize links with scoped-slots:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
<template #link="{ href, title }">
<a :href="href">{{ title }}</a>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<slot name="link" :href="link.href" :title="link.title" />
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
So the looped links are passed through the slot so the parent is handling the rendering

How to add spaces between different tags

I have some code that looks like this
<div class="topnav">
<div>{{getGameView.Game.gameplayers[0].player.username}}</div>
<p>VS</p>
<div v-if="getGameView.Game.gameplayers.length > 1">
  {{getGameView.Game.gameplayers[1].player.username}}
 </div>
<div v-else>Waiting for opponent...</div>
</div>
Which prints this: NameVSName
I am trying to make it so that between Name and VS there is some space but cannot figure out how to do it.
A solution is to give to the VS element a class like .vs and add some padding to it:
p {
margin: 0;
}
.topnav {
display: flex;
}
.topnav .vs {
padding-right: 10px;
padding-left: 10px;
}
<div class="topnav">
<div>Name</div>
<p class="vs">VS</p>
<div>Name</div>
</div>
You can insert a space in html with .
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
nameA: "Job",
nameB: "Bob"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ nameA }} Vs {{ nameB }}
</div>
How to insert spaces/tabs in text using HTML/CSS

Tried to apply css to a component conditionally using prop but its not working

.storyMobile{
color:green;
}
.storyWeb{
color:red;
}
<div class="storyMobile">
hii
</div>
<div class="storyWeb">
hii
</div>
//main view
<div>
<story :story="stories[0]"/>
</div>
//here it prints stories in red colour but I want it to be displayed in green colour - how can I do this?
This is my component where I have 2 divs with 2 different classes one will be active for mobile and one will be active for web.
<div class="storyMobile">
//code
</div>
<div class="storyWeb">
//code
</div>
//this is my main view where I am importing this component
<div class="body-frame">
<Header></Header>
<section class="content-section-bar" v-if="stories && stories.length">
<div>
<story :story="stories[0]"/>
</div>
</section>
</div>
By default the story component is in web so "storyweb" class is getting applied to it but I want the "storyweb" class to get applied on it.
How should I do it in vue.js I tried using the props but didn't get the desired output.
Is it what you want?
your component:
<div :class="className"></div>
script:
export default {
props: {
className: {
default: 'storyWeb'
}
}
}
usage:
<story :story="stories[0]"/>
<story :story="stories[0]" class-name="storyMobile"/>
Vue.component('story',{
template: `<div :class="className">test</div>`,
props: {
className: {
type: String,
default: 'storyWeb'
},
story: {
type: Object,
required: true
}
}
})
var app = new Vue({
el: '#app',
data () {
return {
stories: [
{content: 'sotry1 content'},
{content: 'story2 content'}
]
}
}
})
.storyMobile{
color:green;
}
.storyWeb{
color:red;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<story :story="stories[0]" class-name="storyMobile"></story>
<story :story="stories[1]"></story>
</div>

CSS - How to have swiper slider arrows outside of slider that takes up 12 column row

I am using swiper slider and would like to have navigation arrows outside of the slider. What I would basically like to do is the same as it looks like on airbnb site, where slider with images takes up whole 12 column row, but arrows are outside of it.
I am using bootstrap twitter css framework and I have tried various things but nothing worked and don't know how to achieve this?
The css is this:
.swiper-container {
margin-top: 50px;
position: relative;
}
.arrow-left {
position: absolute;
top: 50%;
left: 0;
}
.arrow-right {
position: absolute;
top: 50%;
right: 0;
}
Html looks like this:
<div class="row swiper-container">
<div class="arrow-left">
<i class="ion-chevron-left"></i>
</div>
<div class="col-md-12 swiper-wrapper">
#foreach($videos as $video)
<div class="swiper-slide video-card">
<header class="card__thumb">
<img src="{{ $video->getThumbnail() }}"/>
</header>
<div class="card__body">
<div class="card__category">
</div>
<small>
{{ $video->created_at->diffForHumans() }}
</small>
<span class="video-title">
<p>
#if($video->title != '')
{{ $video->title }} <i class="ion-arrow-right-c"></i>
#else
Untitled
#endif
</p>
</span>
</div>
</div>
#endforeach
</div>
<div class="arrow-right">
<i class="ion-chevron-right"></i>
</div>
</div>
And this is the script:
var carousel = function carousel() {
var mySwiper = new Swiper ('.swiper-container', {
direction: 'horizontal',
nextButton: '.arrow-left',
prevButton: '.arrow-right',
slidesPerView: 4,
simulateTouch: false,
spaceBetween: 15,
breakpoints: {
1181: {
slidesPerView: 4
},
1180: {
slidesPerView: 3
},
1020: {
slidesPerView: 2
},
700: {
slidesPerView: 1
}
}
});
};
$(document).ready(function () {
carousel();
});
I just did this for one of my current projects.
You just have to change the location of the navigation HTML buttons and put them outside the swiper-container. For a better approach and behavior from the library, add a new class to them, and change the element in the JavaScript call.
Example:
<div class="swiper-container">
<div class="swiper-slides"></div>
</div>
<div class="swiper-button-prev-unique"></div>
<div class="swiper-button-next-unique"></div>
let carousel = new Swiper('.swiper-container', {
navigation: {
nextEl: '.swiper-button-next-unique',
prevEl: '.swiper-button-prev-unique'
}
});
That worked perfect, and you can put your arrows outside the wrapper with ease with CSS.
For all my React folks out there:
import { Swiper as SwiperClass } from 'swiper/types';
import { Swiper, SwiperSlide } from 'swiper/react';
export const MySwiper = () => {
const [swiperRef, setSwiperRef] = useState<SwiperClass>();
const theSlides = useMemo(()=> ['slide one', 'slide two'], [])
const handlePrevious = useCallback(() => {
swiperRef?.slidePrev();
}, [swiperRef]);
const handleNext = useCallback(() => {
swiperRef?.slideNext();
}, [swiperRef]);
return (
<div>
<div>
<button onClick={handlePrevious }>
previous
</button>
</div>
<Swiper
onSwiper={setSwiperRef}
>
{theSlides.map((slide) => (<SwiperSlide key={slide}>{slide}</SwiperSlide>)
</Swiper>
<div>
<button onClick={handleNext}>
Next
</button>
</div>
</div>
);
};
If you using multiple swipers then you need to add different class names to swiper-cotainer and pagination arrows. And then create new Swiper and bind each arrows to local swiper.
let arr_next = $('.template-next') //your arrows class name
let arr_prev = $('.template-prev') //your arrows class name
$('.swiper-container--template').each(function (index, element) {
$(this).addClass('swiper' + index);
arr_next[index].classList.add('template-next' + index);
arr_prev[index].classList.add('template-prev' + index);
new Swiper('.swiper' + index, {
slidesPerView: 2,
navigation: {
nextEl: '.template-next'+index,
prevEl: '.template-prev'+index
},
slidesPerView: 2,
//spaceBetween: 100,
loop: true,
breakpoints: {
961: { slidesPerView: 2 },
740: { slidesPerView: 1 },
},
});
});
`
var swiper = new Swiper('.swiper-container', {
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev',
slidesPerView: 3,
spaceBetween: 10,
autoplay: 3500,
autoplayDisableOnInteraction: false,
loop: true,
breakpoints: {
1024: {
slidesPerView: 3,
spaceBetween: 40
},
768: {
slidesPerView: 3,
spaceBetween: 30
},
640: {
slidesPerView: 2,
spaceBetween: 20
},
320: {
slidesPerView: 1,
spaceBetween: 10
}
}
});
.container{max-width: 600px;margin: 0 auto;}
.swiper_wrap{padding:0px 50px;height:100%;width: 100%;position: relative;display: block;text-align: left;}
.swiper-button-next{
margin-top: 0px;
position: absolute;
top: 50%;
right: -40px;
width: 45px;
height: 45px;
transform: translateY(-50%);
}
.swiper-button-prev{
position: absolute;
top: 50%;
left: -40px;
width: 45px;
height: 45px;
transform: translateY(-50%);
margin-top: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/js/swiper.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/css/swiper.min.css" rel="stylesheet"/>
<div class="container">
<div class="swiper_wrap">
<div class="slider-wrapper">
<div class="swiper-button-prev"></div>
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a href="#">
<img src="http://redsqdesign.co.uk/wp-content/uploads/2017/02/red-square.png">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="http://redsqdesign.co.uk/wp-content/uploads/2017/02/red-square.png">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="http://redsqdesign.co.uk/wp-content/uploads/2017/02/red-square.png">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="http://redsqdesign.co.uk/wp-content/uploads/2017/02/red-square.png">
</a>
</div><div class="swiper-slide">
<a href="#">
<img src="http://redsqdesign.co.uk/wp-content/uploads/2017/02/red-square.png">
</a>
</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
</div>
<div class="swiper-button-next"></div>
</div>
</div>
</div>
<script src="http://www.jakse.si/test/jakse/taxi/js/swiper.min.js"></script>
This works for me, it is the same like older answer, but maybe it looks better :)
Put this below swiper block:
.section {
.swiper-button-prev {
left: -20px;
}
.swiper-button-next {
right: -20px;
}
}
<div class="section">
<div class="swiper">
<ul class="swiper-wrapper">
<li class="swiper-slide">
</li>
</ul>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
if anyone is interested I've found an easy work-around for this issue
position: fixed; will override the overflow:hidden; of the parent but it will make it appear relative to the root element, adding transform to the wrapper will make it relative again to the parent.
new Swiper(".my-swiper", {
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
}
});
.custom-swiper-wrapper {
transform: translate(0, 0);
.swiper-custom-nav {
position: fixed;
}
}
<div class="container custom-swiper-wrapper">
<div class="swiper my-swiper">
<div class="swiper-wrapper">
swiper items here
</div>
<div class="swiper-button-next swiper-custom-nav"></div>
<div class="swiper-button-prev swiper-custom-nav"></div>
</div>
</div>
This is a general solution. To move your arrows outside the container you'll need to first remove the arrow divs from .swiper-container.
Make another bigger container that has .swiper-container and your moved arrows. Give this bigger container position: relative as a reference to arrows that have position: absolute.
Make sure that the .swiper-container width is changed to a value smaller than 100% (e.g. 90% 95%) to avoid overlapping with the arrows.
If you like to keep the .swiper-container width same as that of the entire page width then give -ve margin to the bigger container.
This works if slidesPerView = 1:
.swiper-container {
padding-left: 50px;
padding-right: 50px;
}
.swiper-slide {
visibility: hidden;
}
.swiper-slide.swiper-slide-active {
visibility: visible;
}
In the wrapper function "carousel" we are using to initialize our Swiper instance we can use Swiper's native methods slideNext and slidePrev to add event listeners explicitly to ONLY children of a shared parent element.
1020: {
slidesPerView: 2
},
700: {
slidesPerView: 1
}
}
});
mySwiper.el.parentElement.querySelector(".arrow-left").addEventListener('click',
() => mySwiper.slideNext());
mySwiper.el.parentElement.querySelector(".arrow-right").addEventListener('click',
() => mySwiper.slidePrev());
};
For this to work fully, .swiper-container, .arrow-right and .arrow-left will need to share a wrapper. In Leff's case ".swiper-container" should work just fine:
<div class="row swiper-container">
<div class="arrow-left">
Because this approach allows us to isolate selected elements to a shared parent container, this can be safely used as part of a block of code that might appear more than once.
This is the basic example of how to achieve it. You were close. I slightly modified the code to make it visible within the snippet.
$(document).ready(function () {
var carousel = function carousel() {
var mySwiper = new Swiper ('.swiper-container', {
direction: 'horizontal',
nextButton: '.arrow-left',
prevButton: '.arrow-right',
slidesPerView: 4,
simulateTouch: false,
spaceBetween: 15,
breakpoints: {
1181: {
slidesPerView: 4
},
1180: {
slidesPerView: 3
},
1020: {
slidesPerView: 2
},
700: {
slidesPerView: 1
}
}
});
};
carousel();
});
.row.swiper-container {
margin-top: 50px;
position: relative;
width: 70%;
margin: 0 auto;
}
.arrow-left {
position: absolute;
background: gray;
top: 50%;
left: -40px;
width: 20px;
height: 20px;
transform: translateY(-50%);
}
.arrow-right {
position: absolute;
background: gray;
top: 50%;
right: -40px;
width: 20px;
height: 20px;
transform: translateY(-50%);
}
.swiper-wrapper {
margin: 0 auto;
height: 200px;
background: #f00;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.x.x/css/swiper.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.1/js/swiper.jquery.min.js"></script>
<div class="row swiper-container">
<div class="arrow-left">
<i class="ion-chevron-left"></i>
</div>
<div class="col-md-12 swiper-wrapper">
<div class="swiper-slide video-card">
<header class="card__thumb">
<img src="{{ $video->getThumbnail() }}"/>
</header>
<div class="card__body">
<div class="card__category">
</div>
<small>
</small>
<span class="video-title">
<p>
</p>
</span>
</div>
</div>
</div>
<div class="arrow-right">
<i class="ion-chevron-right"></i>
</div>
</div>
Ok, I had another method,
What the guys suggesting will not work with multiple sliders on page.
So, I added another two arrows, which will trigger the real arrows.
the swiper had:
{
navigation: {
nextEl: '.xnext',
prevEl: '.xprev',
}
}
$('.swiper-button-next').click(
function(e){
$(this).parents('.swiper-container').find('.xnext').trigger('click');
});
$('.swiper-button-prev').click(function(e){$(this).parents('.swiper-container').find('.xprev').trigger('click');});
The code below help to use more than one swiper, using one class. (At first I was used this in a php loop of swipers)
const swiperContainers = document.querySelectorAll('#swiper-global-container');
const swipers = document.querySelectorAll('#swiper-global-container .swiper');
swipers.forEach((swiper, index) => {
swiper.classList.add(`swiper-${index}`);
})
swiperContainers.forEach((container, index) => {
container.querySelector('.swiper-button-next').classList.add(`swiper-next-${index}`)
container.querySelector('.swiper-button-prev').classList.add(`swiper-prev-${index}`)
})
swipers.forEach((swiper, index) => {
new Swiper(`.swiper-${index}`, {
navigation: {
nextEl: `.swiper-next-${index}`,
prevEl: `.swiper-prev-${index}`,
},
});
});
html,
body {
margin: 0;
padding: 0;
}
main {
display: flex;
flex-direction: column;
min-width: 1300px;
}
#swiper-global-container {
flex: 1;
position: relative;
max-width: 1250px;
margin: 0 auto;
}
.swiper-slide {
max-height: 50vh;
}
.swiper {
max-width: 1200px;
margin: 0 auto;
}
.swiper-button-prev {
left: -50px !important;
}
.swiper-button-next {
right: -50px !important;
}
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<main>
<div id="swiper-global-container">
<div class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1652961735386-883c83e4d464?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670"
alt="">
</div>
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1572035563691-0944e6a816d5?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670"
alt="">
</div>
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1652697911040-52d0453522a6?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2574"
alt="">
</div>
</div>
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
<div id="swiper-global-container">
<div class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1652721684678-a147a957a03e?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2748"
alt="">
</div>
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1652898756182-04023f4135a1?ixlib=rb-1.2.1&raw_url=true&q=80&fm=jpg&crop=entropy&cs=tinysrgb&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2664"
alt="">
</div>
<div class="swiper-slide">
<img
src="https://images.unsplash.com/photo-1652162539309-c96b2694f02b?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1655"
alt="">
</div>
</div>
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</main>
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css" />
I'm using react so I didn't want to go through the trouble of creating new event handlers for each of the toggles. I came up with a solution where you just add an extra div wrapper to the slide content and add padding:
html
<div class="row swiper-container">
<div class="arrow-left">
<i class="ion-chevron-left"></i>
</div>
<div class="col-md-12 swiper-wrapper">
#foreach($videos as $video)
<div class="swiper-slide video-card">
<div class="video-card-inner">
<header class="card__thumb">
<img src="{{ $video->getThumbnail() }}"/>
</header>
<div class="card__body">
<div class="card__category">
</div>
<small>
{{ $video->created_at->diffForHumans() }}
</small>
<span class="video-title">
<p>
#if($video->title != '')
{{ $video->title }} <i class="ion-arrow-right-c"></i>
#else
Untitled
#endif
</p>
</span>
</div>
</div>
</div>
#endforeach
</div>
<div class="arrow-right">
<i class="ion-chevron-right"></i>
</div>
</div>
css
.arrow-left {
left: 0;
}
.arrow-right {
right: 0;
}
.video-card {
padding: 0rem 2rem;
}
The padding within the slide will create a gap with the .video-card-inner element that will house all of your content, thus allowing the arrows to sit outside of your visible content. You can still achieve this with custom toggles, but it will also work with their default toggles.
Just stumbled upon this issue today, here's my attempt at solving it. Basically it only requires you wrapping .swiper-container inside additional .swiper-container-wrapper, as Swiper allows passing references to HTMLElement instead of selector string. And you also get to keep the class names, no discrete classes required for navigation elements or container.
At this point both navigation elements are placed inside .swiper-container-wrapper, as .swiper-container's siblings.
$('.swiper-container-wrapper').each(function (index, element) {
var swiperContainer = $(element).children('.swiper-container').get(0);
var nextEl = $(element).children('.swiper-button-next').get(0);
var prevEl = $(element).children('.swiper-button-prev').get(0);
new Swiper(swiperContainer, {
navigation: {
nextEl: nextEl,
prevEl: prevEl,
},
});
});