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.