Displaying rich media, product banners, or announcement graphics is a frequent requirement in custom Lightning apps, Experience Cloud portals, and dashboard homepages. While Salesforce offers the standard <lightning-carousel> base component, building a custom slider provides complete control over animation speed, transitions, custom navigation indicators, and responsive layouts.
1. How the Custom Slider Works
The slider architecture relies on three coordinated pieces:
- A Masked Viewport: An outer wrapper configured with
overflow: hiddento hide all images outside the active window. - A Flex Track Container: An inner container holding all image slides horizontally side by side.
- Dynamic Transform Offset: A reactive JavaScript getter that computes the CSS
transform: translateX(-X%)property, sliding the track smoothly whenever the user clicks Next or Previous.
- Slide Transition: Handled via CSS
transform: translateX()withtransition: transform 0.4s ease-in-out. - State Management: Zero manual DOM manipulation; driven by reactive
currentIndexstate. - Navigation Controls: Standard SLDS icon buttons with boundary wrapping (loops smoothly from last to first slide).
- Metadata Target Support: Compatible with App Pages, Record Pages, and Experience Cloud communities.
2. Step-by-Step Implementation
imageSlider.html)Structure the slider viewport, dynamic track, indicator dots, and navigation buttons.
<template>
<lightning-card title="Featured Showcase" icon-name="utility:photo">
<div class="slds-p-around_medium">
<!-- Slider Viewport -->
<div class="slider-viewport">
<!-- Moving Slides Track -->
<div class="slides-track" style={trackTransformStyle}>
<template for:each={images} for:item="image">
<div key={image.id} class="slide-item">
<img src={image.url} alt={image.altText} class="slide-image" />
<div class="slide-caption">
<p class="slds-text-heading_small">{image.heading}</p>
<p class="slds-text-body_small">{image.description}</p>
</div>
</div>
</template>
</div>
<!-- Directional Arrow Controls -->
<lightning-button-icon
icon-name="utility:chevronleft"
variant="border-filled"
alternative-text="Previous Slide"
class="nav-btn nav-btn-prev"
onclick={handlePreviousSlide}>
</lightning-button-icon>
<lightning-button-icon
icon-name="utility:chevronright"
variant="border-filled"
alternative-text="Next Slide"
class="nav-btn nav-btn-next"
onclick={handleNextSlide}>
</lightning-button-icon>
</div>
<!-- Page Indicator Summary -->
<div class="slds-text-align_center slds-m-top_small slds-text-color_weak">
Slide {currentSlideNumber} of {totalSlides}
</div>
</div>
</lightning-card>
</template>
imageSlider.js)Manage index boundaries and compute the horizontal offset style cleanly.
import { LightningElement } from 'lwc';
export default class ImageSlider extends LightningElement {
currentIndex = 0;
images = [
{
id: '1',
url: 'https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&auto=format&fit=crop&q=60',
altText: 'Mountain Range',
heading: 'Alpine Expeditions',
description: 'Discover rugged high-altitude routes and guided tours.'
},
{
id: '2',
url: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800&auto=format&fit=crop&q=60',
altText: 'Tropical Beach',
heading: 'Coastal Escapes',
description: 'Unwind at top-rated seaside getaways.'
},
{
id: '3',
url: 'https://images.unsplash.com/photo-1448375240586-882707db888b?w=800&auto=format&fit=crop&q=60',
altText: 'Deep Forest',
heading: 'Wilderness Trails',
description: 'Explore quiet forest trails and eco-cabins.'
}
];
get totalSlides() {
return this.images.length;
}
get currentSlideNumber() {
return this.currentIndex + 1;
}
// Computes the dynamic horizontal shift for the slide track
get trackTransformStyle() {
return `transform: translateX(-${this.currentIndex * 100}%);`;
}
handlePreviousSlide() {
if (this.currentIndex === 0) {
this.currentIndex = this.images.length - 1; // Wrap around to end
} else {
this.currentIndex -= 1;
}
}
handleNextSlide() {
if (this.currentIndex === this.images.length - 1) {
this.currentIndex = 0; // Wrap around to beginning
} else {
this.currentIndex += 1;
}
}
}
imageSlider.css)Configure layout boundaries, image cropping, captions, and floating control buttons.
.slider-viewport {
position: relative;
width: 100%;
max-width: 720px;
margin: 0 auto;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}
.slides-track {
display: flex;
width: 100%;
transition: transform 0.4s cubic-bezier(0.25, 1, 0.5, 1);
}
.slide-item {
flex: 0 0 100%;
width: 100%;
position: relative;
background-color: #000;
}
.slide-image {
width: 100%;
height: 380px;
object-fit: cover;
display: block;
}
.slide-caption {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0));
color: #ffffff;
padding: 24px 16px 14px;
}
.nav-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 2;
opacity: 0.85;
transition: opacity 0.2s ease;
}
.nav-btn:hover {
opacity: 1;
}
.nav-btn-prev {
left: 12px;
}
.nav-btn-next {
right: 12px;
}
imageSlider.js-meta.xml)
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
</LightningComponentBundle>
3. Common Traps & Performance Best Practices
Writing expressions like
class={activeClass(image)} will throw a template compilation error in LWC. The LWC template compiler strictly disallows function invocations with arguments inside template tags. Instead, manipulate the container track offset using a computed getter (style={trackTransformStyle}) or pre-compute flags on the array in JavaScript.
- Use Static Resources for Local Assets: If images are bundled with your application rather than pulled from external URLs, load them using
@salesforce/resourceUrl/MyImagesto ensure reliable caching. - Enforce Consistent Aspect Ratios: Apply
object-fit: coverto the<img>element to prevent layout distortion when source images have varying dimensions. - Accessibility Best Practice: Always provide meaningful
alttext on slide images and includealternative-textattributes on button icons so screen readers convey navigation actions clearly.
Summary
Building a custom image slider carousel in Lightning Web Components provides a clean, responsive way to showcase visual content on the Salesforce platform. By leveraging reactive JavaScript getters and hardware-accelerated CSS flexbox transforms, you get smooth transitions, clean component architecture, and an adaptable carousel that fits any Lightning page.
Comments
Questions, corrections and your own experience are all welcome.
Post a Comment