Experience the powerful AI writing right inside WordPress
Show stunning before-and-after transformations with image sliders.
Improve user engagement by showing estimated reading time.
Written by Mahmuda Akter Isha
Showcase Designs Using Before After Slider.
To add dots to a carousel, create one indicator button for each slide and connect every button to its corresponding slide.
A carousel can help you present multiple images, products, testimonials, portfolio items, or announcements without taking up too much page space. However, visitors may not realize that more slides are available when a carousel only includes an image and two small arrows.
Carousel dots solve this problem by showing the number of slides, identifying the active slide, and allowing visitors to jump directly to a specific item.
You can add carousel dots through your WordPress slider settings, Bootstrap carousel indicators, a JavaScript slider library, or custom HTML, CSS, and JavaScript. The correct method depends on how your carousel was created.
This guide explains how to add, style, and troubleshoot carousel dots across the most common platforms.
Carousel dots are small navigation controls that appear above, below, or over a carousel. Each dot represents a slide or group of slides.
The selected dot usually has a different color, size, border, or shape to show which slide is currently active.
Carousel dots are also called:
The W3C describes them as slide picker controls: a group of elements, often displayed as small dots, that allow users to choose a specific slide.
Dots are not required for every carousel, but they can make navigation clearer and more predictable.
A visitor may assume that the first image is static when there is no visible navigation. Dots immediately indicate that the component contains multiple slides.
An active dot helps visitors understand whether they are viewing the first, middle, or final slide.
Without dots, a user may need to click the next arrow several times to reach a particular slide. Navigation dots let the user jump directly to it.
Dots provide a compact navigation method that works well on smaller screens, especially when arrow controls would cover part of the image.
Clear visual feedback helps users recognize that their click, swipe, or keyboard action changed the slide.
Dots and arrows serve different purposes.
Arrows move the carousel backward or forward one step at a time. Dots show the number of slides and allow direct navigation.
For a small carousel containing three to six slides, dots may be enough. For a product carousel, portfolio, testimonial slider, or gallery with several items, using both arrows and dots often creates a clearer experience.
Consider replacing dots with a numerical slide counter when the carousel contains many slides. Twenty or thirty tiny dots can become crowded, difficult to select, and confusing on mobile devices.
A counter such as 3 / 15 may work better for a large gallery.
Many WordPress slider blocks, carousel widgets, and gallery plugins include built-in pagination controls. You usually do not need to write code.
The exact option name depends on the plugin or page builder.
From your WordPress dashboard, go to Pages or Posts and edit the content containing your slider.
Open it with the editor used to build the page, such as:
Click the carousel, image slider, testimonial slider, product slider, or gallery block.
The related settings should appear in the sidebar or widget panel.
Look for a section named:
Turn on the option labeled:
Save or update the page after enabling it.
Depending on the plugin, you may be able to adjust:
View the page on the front end and test every dot.
Check that:
First, check whether the feature is available only in another navigation tab or premium version of the plugin.
You can also:
Avoid editing a plugin’s core files. Plugin updates can overwrite those changes.
Bootstrap calls carousel dots indicators.
Bootstrap 5 uses button elements and data-bs-* attributes for its carousel controls. This differs from older Bootstrap 4 examples that use list items, data-target, and data-slide-to.
data-bs-*
data-target
data-slide-to
Bootstrap recommends giving every carousel a unique ID and matching each indicator’s data-bs-target value to that ID. One slide must also have the .active class or the carousel will not be visible.
data-bs-target
.active
Make sure Bootstrap 5 CSS and the Bootstrap JavaScript bundle are loaded in your project. Then add the following markup:
<div id="projectCarousel" class="carousel slide" aria-label="Featured projects" > <div class="carousel-indicators"> <button type="button" data-bs-target="#projectCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Show project 1" ></button> <button type="button" data-bs-target="#projectCarousel" data-bs-slide-to="1" aria-label="Show project 2" ></button> <button type="button" data-bs-target="#projectCarousel" data-bs-slide-to="2" aria-label="Show project 3" ></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img src="project-1.jpg" class="d-block w-100" alt="Completed living room renovation" > </div> <div class="carousel-item"> <img src="project-2.jpg" class="d-block w-100" alt="Modern office interior design" > </div> <div class="carousel-item"> <img src="project-3.jpg" class="d-block w-100" alt="Outdoor restaurant seating area" > </div> </div> <button class="carousel-control-prev" type="button" data-bs-target="#projectCarousel" data-bs-slide="prev" > <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">Previous slide</span> </button> <button class="carousel-control-next" type="button" data-bs-target="#projectCarousel" data-bs-slide="next" > <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">Next slide</span> </button> </div>
Bootstrap’s official carousel pattern also uses buttons for indicators and lets visitors jump directly to a selected slide.
Each indicator contains a data-bs-slide-to value.
data-bs-slide-to
The values begin at zero:
data-bs-slide-to="0"
data-bs-slide-to="1"
data-bs-slide-to="2"
The first indicator includes:
class="active" aria-current="true"
This identifies the initially selected indicator.
The first .carousel-item must also contain the .active class.
.carousel-item
For every new slide, add another indicator button.
For a fourth slide, add:
<button type="button" data-bs-target="#projectCarousel" data-bs-slide-to="3" aria-label="Show project 4" ></button>
Then add the corresponding fourth .carousel-item inside .carousel-inner.
.carousel-inner
The slide index and indicator index must match.
Bootstrap indicators are often displayed as short bars by default. You can turn them into circular dots with CSS.
#projectCarousel .carousel-indicators { gap: 8px; margin-bottom: 1rem; } #projectCarousel .carousel-indicators [data-bs-target] { width: 12px; height: 12px; margin: 0; border: 0; border-radius: 50%; background-color: #ffffff; opacity: 0.55; } #projectCarousel .carousel-indicators .active { opacity: 1; transform: scale(1.2); }
Scoping the styles with #projectCarousel prevents them from changing every Bootstrap carousel on the website.
#projectCarousel
Bootstrap positions indicators over the carousel by default. To place them below the images, use:
#projectCarousel { padding-bottom: 42px; } #projectCarousel .carousel-indicators { bottom: 0; margin-bottom: 8px; } #projectCarousel .carousel-indicators [data-bs-target] { background-color: #333333; }
Add enough bottom padding so the dots do not overlap the slide content.
You can build your own carousel when you do not use Bootstrap, WordPress, or another slider library.
The following example:
<section class="dot-carousel" data-carousel role="region" aria-roledescription="carousel" aria-label="Featured design projects" > <div class="dot-carousel__viewport"> <div class="dot-carousel__track" data-carousel-track> <article class="dot-carousel__slide" data-carousel-slide role="group" aria-roledescription="slide" aria-label="1 of 3" > <img src="design-1.jpg" alt="Minimal bedroom interior"> </article> <article class="dot-carousel__slide" data-carousel-slide role="group" aria-roledescription="slide" aria-label="2 of 3" > <img src="design-2.jpg" alt="Bright contemporary kitchen"> </article> <article class="dot-carousel__slide" data-carousel-slide role="group" aria-roledescription="slide" aria-label="3 of 3" > <img src="design-3.jpg" alt="Modern home office"> </article> </div> </div> <div class="dot-carousel__controls"> <button class="dot-carousel__arrow" type="button" data-carousel-prev aria-label="Show previous slide" > ← </button> <div class="dot-carousel__dots" data-carousel-dots aria-label="Choose a slide" ></div> <button class="dot-carousel__arrow" type="button" data-carousel-next aria-label="Show next slide" > → </button> </div> </section>
Replace the image file names and alternative text with your own content.
.dot-carousel { width: min(100%, 900px); margin-inline: auto; } .dot-carousel__viewport { overflow: hidden; border-radius: 12px; } .dot-carousel__track { display: flex; transition: transform 0.45s ease; } .dot-carousel__slide { flex: 0 0 100%; min-width: 0; } .dot-carousel__slide img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; } .dot-carousel__controls { display: flex; justify-content: center; align-items: center; gap: 16px; margin-top: 16px; } .dot-carousel__dots { display: flex; justify-content: center; align-items: center; gap: 9px; } .dot-carousel__dot { width: 12px; height: 12px; padding: 0; border: 2px solid #333333; border-radius: 50%; background: transparent; cursor: pointer; transition: background-color 0.2s ease, transform 0.2s ease; } .dot-carousel__dot:hover { background-color: #777777; } .dot-carousel__dot[aria-current="true"] { background-color: #333333; transform: scale(1.2); } .dot-carousel__dot:focus-visible, .dot-carousel__arrow:focus-visible { outline: 3px solid currentColor; outline-offset: 3px; } .dot-carousel__arrow { min-width: 44px; min-height: 44px; border: 1px solid #cccccc; border-radius: 50%; background: #ffffff; cursor: pointer; font-size: 1.25rem; } @media (prefers-reduced-motion: reduce) { .dot-carousel__track, .dot-carousel__dot { transition: none; } }
The arrow buttons use a minimum target size of 44 by 44 pixels, making them easier to select on touchscreens.
document.querySelectorAll("[data-carousel]").forEach((carousel) => { const track = carousel.querySelector("[data-carousel-track]"); const slides = Array.from( carousel.querySelectorAll("[data-carousel-slide]") ); const dotsContainer = carousel.querySelector("[data-carousel-dots]"); const previousButton = carousel.querySelector("[data-carousel-prev]"); const nextButton = carousel.querySelector("[data-carousel-next]"); if ( !track || !dotsContainer || !previousButton || !nextButton || slides.length === 0 ) { return; } let currentIndex = 0; const dots = slides.map((slide, index) => { const dot = document.createElement("button"); dot.type = "button"; dot.className = "dot-carousel__dot"; dot.setAttribute("aria-label", `Show slide ${index + 1}`); dot.addEventListener("click", () => { showSlide(index); }); dotsContainer.appendChild(dot); return dot; }); function showSlide(index) { currentIndex = (index + slides.length) % slides.length; track.style.transform = `translateX(-${currentIndex * 100}%)`; slides.forEach((slide, slideIndex) => { const isActive = slideIndex === currentIndex; slide.setAttribute("aria-hidden", String(!isActive)); slide.inert = !isActive; }); dots.forEach((dot, dotIndex) => { const isActive = dotIndex === currentIndex; if (isActive) { dot.setAttribute("aria-current", "true"); } else { dot.removeAttribute("aria-current"); } }); } previousButton.addEventListener("click", () => { showSlide(currentIndex - 1); }); nextButton.addEventListener("click", () => { showSlide(currentIndex + 1); }); carousel.addEventListener("keydown", (event) => { if (event.key === "ArrowLeft") { event.preventDefault(); showSlide(currentIndex - 1); } if (event.key === "ArrowRight") { event.preventDefault(); showSlide(currentIndex + 1); } }); showSlide(0); });
The script searches for every element containing the data-carousel attribute. This makes it possible to use more than one carousel on the same page.
data-carousel
It then:
translateX()
aria-current="true"
Swiper calls its dot navigation pagination.
Add a pagination container to the Swiper markup:
<div class="swiper"> <div class="swiper-wrapper"> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> </div> <div class="swiper-pagination"></div> </div>
Then enable clickable pagination in the Swiper configuration:
const swiper = new Swiper(".swiper", { pagination: { el: ".swiper-pagination", clickable: true } });
Swiper’s modular installation requires the Pagination module and its related styles when you are not using the full bundle.
Slick Slider uses the dots setting.
dots
$(".your-slider").slick({ dots: true, arrows: true, slidesToShow: 1, slidesToScroll: 1 });
The default setting is dots: false, so you must enable it explicitly. Slick also provides options such as appendDots, dotsClass, and customPaging for more control over dot placement and markup.
dots: false
appendDots
dotsClass
customPaging
A common reason Slick dots do not appear is that the theme stylesheet has not been loaded. Make sure both the main Slick stylesheet and the theme styles are included when you depend on the default design.
Owl Carousel supports dot navigation through the dots option.
$(".owl-carousel").owlCarousel({ items: 1, loop: true, dots: true, nav: true });
Add the owl-theme class when you want to use Owl Carousel’s default dot and arrow styles:
owl-theme
<div class="owl-carousel owl-theme"> <div>Slide 1</div> <div>Slide 2</div> <div>Slide 3</div> </div>
Owl Carousel enables dots by default, but its theme stylesheet and owl-theme class are needed for the standard visual design.
The exact selector depends on the carousel platform, but the styling principles are similar.
.carousel-dot { background-color: #b8b8b8; }
.carousel-dot.active { background-color: #222222; }
For an accessible custom carousel using aria-current, use:
aria-current
.carousel-dot[aria-current="true"] { background-color: #222222; }
.carousel-dot { width: 14px; height: 14px; }
Keep enough space between dots so visitors do not accidentally select the wrong one.
.carousel-dot { border-radius: 50%; }
The width and height should be equal to create a perfect circle.
A wider active indicator can make the selected state easier to recognize.
.carousel-dot { width: 10px; height: 10px; border-radius: 999px; transition: width 0.2s ease; } .carousel-dot[aria-current="true"] { width: 28px; }
The cleanest method is to use the gap property on the parent:
gap
.carousel-dots { display: flex; gap: 10px; }
.carousel-dots { display: flex; justify-content: center; align-items: center; }
Keep the dots in a separate container after the slide viewport:
.carousel-dots { position: static; margin-top: 16px; }
This often produces better readability than positioning them over a busy image.
.carousel-dot:focus-visible { outline: 3px solid #111111; outline-offset: 3px; }
Do not remove the browser’s focus outline unless you replace it with an equally visible alternative.
@media (min-width: 1024px) { .carousel-dots { display: none; } }
Only hide them when another clear navigation method, such as arrows or thumbnail controls, remains available.
Carousel dots should remain easy to see and select on mobile devices.
Use these practices:
Very small dots placed close together are difficult to select accurately. Increase the clickable area with padding or use a larger button containing a smaller visual circle.
.carousel-dot { width: 32px; height: 32px; padding: 0; border: 0; background: transparent; position: relative; } .carousel-dot::before { content: ""; position: absolute; inset: 10px; border-radius: 50%; background-color: #999999; }
This creates a 32-pixel button while keeping the visible circle small.
Multiple rows make the carousel position harder to understand.
For a large number of slides, consider:
White dots may disappear over bright photographs, while dark dots may disappear over dark images.
Place them below the image or add a contrasting background behind the controls.
Carousel accessibility involves more than adding aria-label attributes.
aria-label
The carousel must remain understandable and controllable for keyboard users, screen-reader users, touch users, and people who are sensitive to motion.
A dot performs an action, so it should usually be a <button>.
<button>
Avoid using an empty <span> as the clickable control. A native button already supports keyboard focus and activation.
<span>
The W3C recommends native button elements for carousel controls when possible.
<button type="button" aria-label="Show slide 2"></button>
A screen reader should not announce an unexplained “button” for every indicator.
<button type="button" aria-label="Show slide 1" aria-current="true" ></button>
Update aria-current whenever the active slide changes.
The active dot can also be:
This helps visitors who cannot easily distinguish the selected color.
A keyboard user must be able to see which control is focused.
<section role="region" aria-roledescription="carousel" aria-label="Customer success stories" >
Use a label that describes the content rather than a generic label such as “slider.”
When descriptive slide titles are unavailable, labels such as 1 of 5, 2 of 5, and 3 of 5 can communicate position.
1 of 5
2 of 5
3 of 5
Automatically rotating content can become confusing when visitors do not have enough time to read or interact with a slide.
According to the W3C carousel pattern, an automatically rotating carousel should provide a stop-and-start control. Rotation should stop when keyboard focus enters the carousel and while the pointer is hovering over it. It should not restart after keyboard focus enters unless the user explicitly requests it.
The simplest accessible option is often to disable autoplay.
@media (prefers-reduced-motion: reduce) { .carousel-track { transition: none; } }
This reduces unnecessary motion for visitors who have enabled reduced-motion settings on their devices.
Carousel dots can fail because of incorrect settings, missing files, conflicting CSS, or mismatched slide indexes.
Check whether pagination has been enabled in the slider settings.
Also verify that:
display: none
overflow: hidden
Use your browser’s developer tools to inspect the dots container.
If the elements exist but cannot be seen, the problem is probably CSS. If the elements do not exist, the carousel configuration or JavaScript initialization may be the cause.
Possible causes include:
pointer-events: none
Inspect the dot with developer tools and check whether another element is positioned above it.
You can temporarily test layering with:
.carousel-dots { position: relative; z-index: 10; }
Do not use an unnecessarily high z-index as a permanent fix without identifying the overlapping element.
z-index
Most carousel libraries use zero-based indexes.
That means:
0
1
2
Make sure every dot uses the correct slide index.
Also check whether multiple carousels are using the same ID or global JavaScript selectors.
The active state must change after every navigation method, including:
When using a slider library, listen for its slide-change event rather than updating the dots only when they are clicked.
Check that you are not mixing Bootstrap 4 and Bootstrap 5 syntax.
Bootstrap 5 uses:
data-bs-target data-bs-slide data-bs-slide-to
Older Bootstrap 4 examples use:
data-target data-slide data-slide-to
The indicator target must match the carousel ID exactly.
For example:
id="projectCarousel"
must be connected to:
data-bs-target="#projectCarousel"
Use flexbox on the parent container:
.carousel-dots { display: flex; justify-content: center; align-items: center; gap: 8px; }
Remove conflicting left, right, float, or fixed-width styles when necessary.
left
right
float
Move the dots below the carousel or add bottom spacing.
.carousel { padding-bottom: 48px; } .carousel-dots { bottom: 8px; }
Check the design on mobile because captions may become taller when text wraps.
Your custom CSS may be targeting the wrong active selector.
Common selectors include:
.active [aria-current="true"] .swiper-pagination-bullet-active .slick-active .owl-dot.active
Inspect the selected dot after changing slides to identify the exact class added by your carousel.
You may also need a more specific selector when your styles are being overridden.
Make sure:
dots: true
.slick-dots
Swiper bullets are not necessarily clickable unless the option is enabled:
pagination: { el: ".swiper-pagination", clickable: true }
Also make sure the Pagination module and related CSS have been imported in modular projects.
Add the theme class:
<div class="owl-carousel owl-theme">
Also load:
owl.theme.default.min.css
The dots may exist without the visual theme styles.
Do not simply make every dot extremely small.
Instead, consider:
The navigation should remain understandable and easy to select.
Good carousel pagination should help users without distracting them from the slide content.
Use the same dot style across similar carousels on your website.
The active dot should be recognizable immediately. Use sufficient contrast and consider combining color with size or shape.
Dots should not cover faces, text, product details, calls to action, or comparison areas.
The visible dot can be small, but the interactive button should be comfortable to select.
Clicking the third dot should always display the third slide or slide group.
Visitors should be able to navigate manually and remain on a slide long enough to understand it.
A carousel that works with placeholder images may fail when captions have different lengths or images use different aspect ratios.
Test the final component with:
Adding dots to a carousel gives visitors a clearer way to understand and navigate your slider.
WordPress users can usually enable dots through a block, widget, or plugin setting. Bootstrap 5 users can add indicator buttons connected through data-bs-target and data-bs-slide-to. Developers building a custom carousel can generate accessible buttons with JavaScript and update the active state whenever the slide changes.
Regardless of the method you choose, make sure the dots are visible, clickable, responsive, and keyboard accessible. Use a strong active state, provide sufficient spacing, and avoid overwhelming mobile users with too many indicators.
A well-designed set of carousel dots does more than decorate a slider. It helps users discover additional content, understand their current position, and move directly to the slide that interests them.
They are commonly called carousel dots, slider dots, navigation dots, pagination dots, carousel indicators, pagination bullets, or slide picker controls.The terminology depends on the platform. Bootstrap calls them indicators, while Swiper calls them pagination bullets.
Enable the slider’s pagination setting or create one button for each image. Connect each button to the corresponding slide and update its active state whenever the visible image changes.
Edit the carousel block or widget, open its Navigation or Pagination settings, and enable Dots, Bullets, or Indicators. The exact option name depends on your plugin or page builder.
Add a .carousel-indicators container and place one button inside it for each slide. Each button needs a data-bs-target matching the carousel ID and a data-bs-slide-to value matching the slide index.
.carousel-indicators
The pagination option may be disabled, the required stylesheet may be missing, the dots may be hidden by CSS, or the carousel may not have initialized correctly.Inspect the page to determine whether the dot elements exist in the HTML.
Place the dots container after the carousel viewport and remove absolute positioning. Alternatively, add bottom padding to the carousel and position the indicators inside that space.
Yes. Dots are most useful when visitors can select them to open a specific slide. Use button elements and provide accessible labels for each control.
This page was last edited on 20 July 2026, at 5:34 pm
Your email address will not be published. Required fields are marked *
Comment *
Name *
Email *
Website
Save my name, email, and website in this browser for the next time I comment.
How many people work in your company?Less than 1010-5050-250250+
By proceeding, you agree to our Privacy Policy