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.
Create an image slider in WordPress without a plugin by adding custom HTML, CSS, and JavaScript to your page. Upload optimized images, replace the sample URLs, then customize autoplay, captions, navigation buttons, and slider height. Test the slider on mobile and desktop before publishing.
An image slider can help you display a portfolio, product collection, featured content, testimonials, or promotional banners without using a large amount of page space.
Although WordPress has several slider plugins, you do not always need one. You can create a responsive image slider in WordPress without a plugin using a Custom HTML block, CSS, and a small amount of JavaScript.
In this tutorial, you will build a lightweight WordPress image slider with:
The code is scoped to a unique class, so it is less likely to conflict with your WordPress theme or other elements on the page.
An image slider, sometimes called an image slideshow or carousel, displays multiple images within one section of a webpage. Visitors can move between the images using arrows, navigation dots, keyboard controls, or swipe gestures.
A slider may also rotate through its images automatically.
Common uses of a WordPress image slider include:
A slider can make a page visually engaging, but it should not contain information that visitors must see to understand the page. Some users may never move beyond the first slide, so your most important content should remain outside the slider or appear on the first slide.
A plugin is usually the easiest option for advanced sliders. However, creating a simple image slider manually can provide several advantages.
Some slider plugins include dozens of templates, animations, integrations, and controls. If you only need a basic image slideshow, much of that code may be unnecessary.
A custom slider lets you load only the HTML, CSS, and JavaScript required for your design.
You can control every part of a custom slider, including:
You are not limited to the settings provided by a plugin.
A manually created slider does not depend on a third-party plugin remaining active, compatible, and maintained.
You will still need to review your custom code when making major changes to your WordPress theme, but you retain complete control over it.
Building the slider is also a practical way to understand how HTML, CSS, and JavaScript work together inside WordPress.
Creating a slider without a plugin is ideal for a small, static collection of images. A plugin may be the better option when you need:
Choose the simplest solution that meets the actual requirements of your website.
Complete these preparations before adding the code.
Create a recent backup before editing site-wide CSS, JavaScript, or theme files.
For an established website, test the slider on a staging site before adding it to a live page.
For the most consistent appearance, use images with the same aspect ratio.
A practical starting size is:
You can use a different ratio, but all slider images should ideally use the same dimensions.
Large slider images can slow down the page, especially on mobile devices.
Before uploading them:
For example, use:
wordpress-image-slider-example.webp
Instead of:
IMG_4829.webp
Alternative text should explain the content or purpose of an image to someone who cannot see it.
Use specific descriptions such as:
A responsive photography portfolio displayed in a WordPress image slider
Avoid keyword stuffing or descriptions such as:
Image slider WordPress slider best WordPress slider image
If an image is purely decorative and its meaning is already provided in nearby text, an empty alt="" value may be more appropriate.
alt=""
Log in to your WordPress dashboard and follow these steps:
Keep the image URLs somewhere accessible. You will replace the sample URLs in the HTML code with these addresses.
Open the page or post where you want the image slider to appear.
You can also type /html in an empty paragraph and select the Custom HTML block.
/html
In newer WordPress versions, the Custom HTML block may provide separate areas for HTML, CSS, and JavaScript. WordPress documentation states that separate editing panels are available beginning with WordPress 7.0. Availability may also depend on the user’s permissions and the site configuration.
Paste the following code into the HTML area of the Custom HTML block:
<div class="cc-image-slider" role="region" aria-roledescription="carousel" aria-label="Featured image gallery" data-autoplay="true" data-interval="5000" > <div class="cc-slider__viewport"> <div class="cc-slider__track"> <figure class="cc-slider__slide" aria-roledescription="slide" > <img src="URL_OF_YOUR_IMAGE_1" alt="Describe the first image" width="1200" height="675" decoding="async" fetchpriority="high" > <figcaption class="cc-slider__caption"> Add a short caption for the first image. </figcaption> </figure> <figure class="cc-slider__slide" aria-roledescription="slide" > <img src="URL_OF_YOUR_IMAGE_2" alt="Describe the second image" width="1200" height="675" loading="lazy" decoding="async" > <figcaption class="cc-slider__caption"> Add a short caption for the second image. </figcaption> </figure> <figure class="cc-slider__slide" aria-roledescription="slide" > <img src="URL_OF_YOUR_IMAGE_3" alt="Describe the third image" width="1200" height="675" loading="lazy" decoding="async" > <figcaption class="cc-slider__caption"> Add a short caption for the third image. </figcaption> </figure> </div> <button class="cc-slider__button cc-slider__button--prev" type="button" aria-label="Show previous slide" > <span aria-hidden="true">‹</span> </button> <button class="cc-slider__button cc-slider__button--next" type="button" aria-label="Show next slide" > <span aria-hidden="true">›</span> </button> </div> <div class="cc-slider__footer"> <div class="cc-slider__dots" role="group" aria-label="Choose a slide" ></div> <button class="cc-slider__pause" type="button"> Pause </button> </div> <p class="cc-slider__status cc-visually-hidden" aria-live="polite" aria-atomic="true" ></p> </div>
Replace these placeholders with your actual WordPress image URLs:
URL_OF_YOUR_IMAGE_1
URL_OF_YOUR_IMAGE_2
URL_OF_YOUR_IMAGE_3
Also replace the alternative text and captions.
The first slide is immediately visible, so it should normally begin loading without waiting for a lazy-loading threshold.
The other images use native lazy loading to reduce unnecessary initial requests. Their real image addresses remain in the src attributes, which helps browsers and search engines discover them without depending on a click or swipe.
src
Google recommends that relevant lazy-loaded content become available when it enters the viewport rather than depending on user actions such as clicking.
Paste the following CSS into the CSS panel of the Custom HTML editor when that option is available:
.cc-image-slider, .cc-image-slider *, .cc-image-slider *::before, .cc-image-slider *::after { box-sizing: border-box; } .cc-image-slider { --cc-slider-radius: 16px; --cc-slider-control-size: 44px; --cc-slider-caption-bg: rgba(0, 0, 0, 0.68); position: relative; width: 100%; max-width: 1200px; margin: 2rem auto; } .cc-slider__viewport { position: relative; overflow: hidden; border-radius: var(--cc-slider-radius); background: #111; } .cc-slider__track { display: flex; width: 100%; transition: transform 450ms ease; will-change: transform; } .cc-slider__slide { position: relative; flex: 0 0 100%; width: 100%; margin: 0; overflow: hidden; aspect-ratio: 16 / 9; } .cc-slider__slide img { display: block; width: 100%; height: 100%; object-fit: cover; } .cc-slider__caption { position: absolute; right: 0; bottom: 0; left: 0; padding: 1rem 1.25rem; color: #fff; font-size: clamp(0.9rem, 2vw, 1.05rem); line-height: 1.5; background: var(--cc-slider-caption-bg); } .cc-slider__button { position: absolute; top: 50%; display: grid; place-items: center; width: var(--cc-slider-control-size); height: var(--cc-slider-control-size); padding: 0; border: 0; border-radius: 50%; color: #111; background: rgba(255, 255, 255, 0.9); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.24); font-size: 2rem; line-height: 1; cursor: pointer; transform: translateY(-50%); } .cc-slider__button:hover { background: #fff; } .cc-slider__button--prev { left: 1rem; } .cc-slider__button--next { right: 1rem; } .cc-slider__footer { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-top: 0.85rem; } .cc-slider__dots { display: flex; flex-wrap: wrap; align-items: center; gap: 0.55rem; } .cc-slider__dot { width: 12px; height: 12px; padding: 0; border: 2px solid currentColor; border-radius: 50%; color: #333; background: transparent; cursor: pointer; } .cc-slider__dot.is-active { background: currentColor; } .cc-slider__pause { min-height: 40px; padding: 0.5rem 0.9rem; border: 1px solid currentColor; border-radius: 6px; color: inherit; background: transparent; font: inherit; cursor: pointer; } .cc-slider__button:focus-visible, .cc-slider__dot:focus-visible, .cc-slider__pause:focus-visible { outline: 3px solid currentColor; outline-offset: 3px; } .cc-visually-hidden { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; white-space: nowrap !important; border: 0 !important; clip: rect(0, 0, 0, 0) !important; clip-path: inset(50%) !important; } @media (max-width: 600px) { .cc-image-slider { --cc-slider-control-size: 38px; --cc-slider-radius: 10px; } .cc-slider__button--prev { left: 0.6rem; } .cc-slider__button--next { right: 0.6rem; } .cc-slider__caption { padding: 0.75rem 1rem; } .cc-slider__footer { align-items: flex-start; } } @media (prefers-reduced-motion: reduce) { .cc-slider__track { transition: none; } }
When your WordPress theme uses the Customizer:
When your site uses a block theme:
WordPress includes a site-wide CSS editor inside the Styles interface for block themes.
Do not paste the complete slider stylesheet into the per-block CSS area. The code contains several custom selectors and should be added to the site-wide Additional CSS field.
Paste the following code into the JavaScript panel of the Custom HTML editor:
document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.cc-image-slider').forEach((slider) => { const track = slider.querySelector('.cc-slider__track'); const slides = Array.from( slider.querySelectorAll('.cc-slider__slide') ); const previousButton = slider.querySelector( '.cc-slider__button--prev' ); const nextButton = slider.querySelector( '.cc-slider__button--next' ); const pauseButton = slider.querySelector( '.cc-slider__pause' ); const dotsContainer = slider.querySelector( '.cc-slider__dots' ); const status = slider.querySelector( '.cc-slider__status' ); if (!track || slides.length === 0) { return; } const autoplayEnabled = slider.dataset.autoplay === 'true'; const interval = Math.max( Number(slider.dataset.interval) || 5000, 3000 ); const reduceMotion = window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; let currentIndex = 0; let timerId = null; let isPaused = reduceMotion || !autoplayEnabled; let touchStartX = 0; const dots = slides.map((slide, index) => { slide.setAttribute( 'aria-label', `${index + 1} of ${slides.length}` ); const dot = document.createElement('button'); dot.type = 'button'; dot.className = 'cc-slider__dot'; dot.setAttribute( 'aria-label', `Show slide ${index + 1}` ); dot.addEventListener('click', () => { goToSlide(index, true); }); dotsContainer?.appendChild(dot); return dot; }); function setFocusableState(slide, isActive) { const focusableElements = slide.querySelectorAll( 'a, button, input, select, textarea, [tabindex]' ); focusableElements.forEach((element) => { if (!isActive) { if ( !element.hasAttribute( 'data-cc-original-tabindex' ) ) { const originalTabindex = element.getAttribute('tabindex'); element.setAttribute( 'data-cc-original-tabindex', originalTabindex === null ? '' : originalTabindex ); } element.setAttribute('tabindex', '-1'); } else if ( element.hasAttribute( 'data-cc-original-tabindex' ) ) { const originalTabindex = element.getAttribute( 'data-cc-original-tabindex' ); if (originalTabindex === '') { element.removeAttribute('tabindex'); } else { element.setAttribute( 'tabindex', originalTabindex ); } element.removeAttribute( 'data-cc-original-tabindex' ); } }); } function updateSlider(announce = false) { track.style.transform = `translateX(-${currentIndex * 100}%)`; slides.forEach((slide, index) => { const isActive = index === currentIndex; slide.setAttribute( 'aria-hidden', String(!isActive) ); setFocusableState(slide, isActive); }); dots.forEach((dot, index) => { const isActive = index === currentIndex; dot.classList.toggle( 'is-active', isActive ); dot.setAttribute( 'aria-current', isActive ? 'true' : 'false' ); }); if (announce && status) { status.textContent = `Slide ${currentIndex + 1} of ${slides.length}`; } } function stopTimer() { window.clearInterval(timerId); timerId = null; } function startTimer() { stopTimer(); if ( !autoplayEnabled || isPaused || slides.length < 2 ) { return; } timerId = window.setInterval(() => { currentIndex = (currentIndex + 1) % slides.length; updateSlider(false); }, interval); } function goToSlide(index, announce = true) { currentIndex = (index + slides.length) % slides.length; updateSlider(announce); startTimer(); } function updatePauseButton() { if (!pauseButton) { return; } pauseButton.hidden = !autoplayEnabled || slides.length < 2; pauseButton.textContent = isPaused ? 'Play' : 'Pause'; pauseButton.setAttribute( 'aria-label', isPaused ? 'Play automatic slideshow' : 'Pause automatic slideshow' ); } previousButton?.addEventListener( 'click', () => { goToSlide(currentIndex - 1, true); } ); nextButton?.addEventListener( 'click', () => { goToSlide(currentIndex + 1, true); } ); pauseButton?.addEventListener( 'click', () => { isPaused = !isPaused; updatePauseButton(); startTimer(); } ); slider.addEventListener( 'keydown', (event) => { if (event.key === 'ArrowLeft') { event.preventDefault(); goToSlide(currentIndex - 1, true); } if (event.key === 'ArrowRight') { event.preventDefault(); goToSlide(currentIndex + 1, true); } if (event.key === 'Home') { event.preventDefault(); goToSlide(0, true); } if (event.key === 'End') { event.preventDefault(); goToSlide(slides.length - 1, true); } } ); slider.addEventListener( 'mouseenter', stopTimer ); slider.addEventListener( 'mouseleave', startTimer ); slider.addEventListener( 'focusin', stopTimer ); slider.addEventListener( 'focusout', (event) => { if (!slider.contains(event.relatedTarget)) { startTimer(); } } ); slider.addEventListener( 'touchstart', (event) => { touchStartX = event.changedTouches[0].clientX; stopTimer(); }, { passive: true } ); slider.addEventListener( 'touchend', (event) => { const touchDistance = event.changedTouches[0].clientX - touchStartX; if (Math.abs(touchDistance) > 50) { goToSlide( currentIndex + (touchDistance < 0 ? 1 : -1), true ); } else { startTimer(); } }, { passive: true } ); document.addEventListener( 'visibilitychange', () => { if (document.hidden) { stopTimer(); } else { startTimer(); } } ); if (slides.length < 2) { previousButton?.setAttribute( 'hidden', '' ); nextButton?.setAttribute( 'hidden', '' ); dotsContainer?.setAttribute( 'hidden', '' ); } updateSlider(false); updatePauseButton(); startTimer(); }); });
The best method depends on your WordPress version, theme, hosting configuration, and user permissions.
When the Custom HTML block provides separate JavaScript editing, paste the code into that panel.
This is the simplest method because the slider code remains connected to the block containing the slider.
On an older WordPress installation, you may be able to place the JavaScript inside <script> tags below the slider HTML:
<script>
<script> // Paste the JavaScript here. </script>
However, WordPress may remove scripts when the user does not have the required unfiltered HTML capability. This is especially relevant on multisite installations or for non-administrator accounts.
After saving the page, reopen the block and confirm that the script is still present.
For a cleaner site-wide implementation, save the JavaScript in a child theme.
Create this file:
/assets/js/codecanel-image-slider.js
Paste the JavaScript into that file.
Then add the following PHP to the child theme’s functions.php file:
functions.php
<?php function codecanel_enqueue_image_slider_script() { wp_enqueue_script( 'codecanel-image-slider', get_stylesheet_directory_uri() . '/assets/js/codecanel-image-slider.js', array(), '1.0.0', array( 'strategy' => 'defer', 'in_footer' => true, ) ); } add_action( 'wp_enqueue_scripts', 'codecanel_enqueue_image_slider_script' );
WordPress recommends loading front-end JavaScript with wp_enqueue_script() instead of manually adding script tags throughout a theme.
wp_enqueue_script()
Use a child theme rather than editing a parent theme directly. Otherwise, a theme update may overwrite your custom file and PHP changes.
Internal link opportunity: Link “child theme” to your existing WordPress child-theme tutorial.
Save the page and open its front-end preview.
Confirm that:
Also test the page while logged out of WordPress. A slider can work in the editor preview but fail on the public page because of caching, optimization, or script-loading settings.
Understanding the code will make it easier to customize.
The .cc-image-slider element contains one complete slider.
.cc-image-slider
Because the JavaScript searches for every element with this class, you can place multiple independent sliders on one page.
The .cc-slider__viewport element hides the slides that are outside the visible area.
.cc-slider__viewport
Its overflow: hidden rule prevents the page from displaying the entire horizontal row.
overflow: hidden
The .cc-slider__track element holds all the slides in a flexible row.
.cc-slider__track
The JavaScript changes its horizontal position with:
transform: translateX(...);
When the active slide changes, the track moves by 100% of the slider width.
Each .cc-slider__slide uses:
.cc-slider__slide
flex: 0 0 100%;
This makes every slide occupy the full width of the viewport.
Unlike approaches that manually set the track to 300%, this method continues to work when you add or remove slides.
300%
The JavaScript automatically creates one navigation dot for every slide. You do not need to add the dot buttons manually.
The active dot receives the .is-active class and an aria-current attribute.
.is-active
aria-current
The data-interval attribute controls the delay between automatic changes.
data-interval
The slider stops its timer when:
The visually hidden status element announces manually selected slides to screen-reader users without placing extra text on the visible design.
Find this line in the opening slider element:
data-interval="5000"
The value is measured in milliseconds.
Examples:
data-interval="3000"
Changes the slide every three seconds.
data-interval="7000"
Changes the slide every seven seconds.
Avoid extremely fast transitions. Visitors need enough time to understand each image and caption.
Change:
data-autoplay="true"
To:
data-autoplay="false"
The play and pause button will be hidden automatically. Visitors can still use the arrows, dots, keyboard commands, and swipe gestures.
Disabling autoplay is often the better choice when slides contain important text.
The slide currently uses a 16:9 aspect ratio:
aspect-ratio: 16 / 9;
For a wider banner, use:
aspect-ratio: 21 / 9;
For a square slider, use:
aspect-ratio: 1 / 1;
For a portrait slider, use:
aspect-ratio: 4 / 5;
The images use:
object-fit: cover;
This fills the available area but may crop the edges of an image.
To show the entire image without cropping, change it to:
object-fit: contain;
This may create empty space around images that do not match the slider’s aspect ratio.
Copy one complete slide:
<figure class="cc-slider__slide" aria-roledescription="slide" > <img src="URL_OF_YOUR_NEW_IMAGE" alt="Describe the new image" width="1200" height="675" loading="lazy" decoding="async" > <figcaption class="cc-slider__caption"> Add a caption for the new image. </figcaption> </figure>
Paste it inside .cc-slider__track.
The JavaScript automatically counts the new slide and creates an additional navigation dot.
You do not need to change a width calculation or update the JavaScript.
Delete the <figcaption> element from each slide:
<figcaption>
<figcaption class="cc-slider__caption"> Add a short caption. </figcaption>
Do not remove the <figure> element or its .cc-slider__slide class.
<figure>
The current caption already appears as a text overlay at the bottom of each image.
You can include a heading and description inside the caption:
<figcaption class="cc-slider__caption"> <strong>Explore Our Latest Project</strong> <span> See how we redesigned this WordPress website. </span> </figcaption>
Add this CSS to display the elements on separate lines:
.cc-slider__caption strong, .cc-slider__caption span { display: block; } .cc-slider__caption strong { margin-bottom: 0.25rem; font-size: 1.15em; }
Keep overlay text concise. Large paragraphs are difficult to read before an automatic transition.
Wrap the image in an anchor element:
<a href="YOUR_DESTINATION_URL"> <img src="URL_OF_YOUR_IMAGE" alt="Describe the destination shown in the image" width="1200" height="675" loading="lazy" decoding="async" > </a>
Use a destination that clearly matches the image and caption.
Avoid opening ordinary internal links in a new browser tab unless there is a specific reason.
The provided JavaScript removes links in hidden slides from the keyboard tab sequence and restores them when their slide becomes active.
Copy the entire .cc-image-slider HTML component and paste it somewhere else on the page.
Replace the images and captions in the copy.
You only need to add the CSS and JavaScript once. The JavaScript initializes every .cc-image-slider separately, so the controls of one slider should not change another slider.
This is an important advantage over code that uses global selectors such as:
document.querySelector('.next');
A global selector usually finds only the first matching button and can cause conflicts when multiple sliders are present.
The process depends on how your homepage is built.
Open the page assigned as the homepage and add the Custom HTML block where you want the slider to appear.
Go to Appearance → Editor, open the homepage or front-page template, and add a Custom HTML block.
Be careful when editing templates because a template-level slider may appear on multiple pages.
Add an HTML or code widget in the page builder. Place the markup in the widget, then add the CSS and JavaScript through the builder’s supported custom-code locations.
Open the post and add a Custom HTML block at the desired location.
Place the slider near the section it supports. Avoid putting a large slider before the introduction unless the images are the primary purpose of the article.
Adding a slider to a header is more advanced because headers are normally controlled by the theme.
With a block theme:
With a classic theme, use a child theme and edit the appropriate header template file.
A header slider may appear across the entire website and can significantly affect page-loading performance. Use it only when the slider is important on every page.
Accessibility should be included in the initial slider design rather than added after publishing.
W3C guidance for carousels recommends allowing visitors to pause movement, operate all functions with a keyboard, and understand when the active slide changes.
The slider in this tutorial includes:
You should also review the content itself.
Describe the purpose or content of each image. Do not repeat the caption word for word unless that is genuinely the best description.
A visitor may not discover every slide. Important instructions, prices, deadlines, warnings, and calls to action should also be available outside the carousel.
Arrow buttons and navigation dots need sufficient contrast against the page and image backgrounds.
The slider includes a pause button and automatically stops while a visitor hovers over it or moves keyboard focus into it.
W3C also recommends pausing carousel animation while the component is hovered or focused.
The CSS removes the transition animation when a visitor has requested reduced motion. The JavaScript also prevents autoplay from starting automatically.
The visitor can still select Play manually.
An image slider is often one of the largest visual elements on a page. Poor image preparation can therefore affect loading speed and visual stability.
Do not upload a 5000-pixel photograph when the slider displays it at approximately 1200 pixels.
Resize images before uploading while retaining enough resolution for larger screens.
Every image in the example contains:
width="1200" height="675"
These attributes help the browser reserve the correct amount of space before the image finishes loading.
This can reduce sudden layout movement.
Images inserted through WordPress’s Image block normally receive responsive srcset and sizes attributes automatically.
srcset
sizes
Because this tutorial uses manually written image markup, you can add responsive attributes yourself when you have multiple generated image sizes:
<img src="image-1200.webp" srcset=" image-480.webp 480w, image-768.webp 768w, image-1200.webp 1200w " sizes="(max-width: 1200px) 100vw, 1200px" alt="Describe the image" width="1200" height="675" >
Only include URLs for files that actually exist.
When the slider appears near the top of the page, the first image may become an important loading element.
The example uses:
fetchpriority="high"
On the first image and does not lazy-load it.
Do not apply high priority to every slide. Doing so can reduce the value of the priority hint and create unnecessary competition between downloads.
Native lazy loading can be useful for slides that are not initially visible.
However, do not create a system in which image URLs are added only after a user clicks an arrow. Google explains that it does not perform user actions such as clicking to reveal lazy-loaded content.
Use an image-compression workflow before publishing.
Compare the final appearance rather than choosing a compression level based only on file size. Excessive compression may make product details, text, or portfolio images appear unclear.
Adding 20 large images can make the slider slow even when later slides are lazy-loaded.
For a homepage or promotional slider, three to five focused slides are usually easier to manage than a large collection.
For a substantial gallery, consider a dedicated gallery layout instead.
Search engines do not depend only on alternative text. Add a useful heading, introductory paragraph, and relevant caption around the slider so the images have clear context.
After publishing, test the page for:
Google describes Core Web Vitals as measurements of loading performance, interactivity, and visual stability.
Compare the results before and after adding the slider.
Possible cause: The CSS did not load or the class names were changed.
Solution:
display: flex
flex: 0 0 100%
Clear your WordPress cache after changing the CSS.
Possible cause: An image URL is incorrect.
Open each image URL directly in a browser. If it returns an error or redirects to a login page, replace it with the public Media Library file URL.
Also confirm that the image is not being blocked by a hotlink-protection or security rule.
Possible cause: The JavaScript did not load.
Check whether:
When using a child theme, confirm that the file path in functions.php matches the actual JavaScript file location.
Possible cause: The code increases the slide index before rendering the initial slide.
The JavaScript in this tutorial starts with index zero and renders that index before starting autoplay.
Avoid calling an increment function before the first render.
Possible cause: The images use different aspect ratios.
The tutorial solves this with:
aspect-ratio: 16 / 9; object-fit: cover;
You can also crop all images to the same dimensions before uploading.
Possible cause: A fixed pixel width was applied to the slider or slides.
Keep the container at width: 100% and use percentage-based slide widths.
width: 100%
Do not change the track to a vertical layout on mobile unless you intentionally want a stacked image gallery instead of a slider.
Possible cause: object-fit: cover is cropping the image.
object-fit: cover
Change it to:
Alternatively, edit the source image so its important subject fits within the chosen aspect ratio.
Possible causes:
data-autoplay
false
Use the Play button to start autoplay when reduced motion initially disables it.
Possible cause: The interval is below the minimum set in the JavaScript.
This line prevents intervals shorter than three seconds:
Math.max( Number(slider.dataset.interval) || 5000, 3000 );
To permit a shorter interval, change 3000, although fast image changes are generally not recommended.
3000
Possible cause: The JavaScript uses selectors that are not scoped to each slider.
Use the complete script from this tutorial. It loops through every slider container and searches for controls only inside the current container.
Possible cause: WordPress removed disallowed script markup.
Use an administrator account with the necessary permissions or enqueue the JavaScript through a child theme.
Do not attempt to bypass site security restrictions. Contact the site administrator when you do not have permission to add scripts.
Possible cause: The site uses a block theme.
Block themes use the Site Editor instead of the classic Customizer. WordPress distinguishes block themes from classic themes and provides block-theme controls through Appearance → Editor.
Use the Styles panel’s site-wide Additional CSS area.
Clear:
Then test the page in a private browser window.
Also confirm that you edited the correct page, template, or theme.
Yes, it is possible to build an image slider using CSS without JavaScript. A CSS-only slider may use radio buttons, anchor targets, scroll snapping, or CSS animations.
However, CSS-only sliders have limitations:
For a basic manually controlled gallery, CSS scroll snapping can be an effective alternative. For arrows, dots, autoplay, pause controls, and active-slide announcements, a small JavaScript component is generally more practical.
Use an image slider when:
Use an image gallery when:
A gallery often provides better visibility because users can see multiple images without operating controls.
Internal link opportunity: Link this section to your carousel-versus-gallery article.
A standard image slider displays separate images one at a time.
A before-and-after slider places two related images in the same frame and lets visitors reveal the difference by dragging a divider.
A before-and-after comparison is more suitable for:
When the purpose is direct visual comparison, use a dedicated before-and-after component rather than a standard slideshow.
Creating an image slider in WordPress without a plugin gives you direct control over its design, behavior, performance, and accessibility.
The process involves three main elements:
The most important part is not simply making the images move. A useful WordPress image slider should also load efficiently, remain responsive, support keyboard users, allow visitors to pause movement, and avoid conflicts with other components.
You can follow the supplied code without writing it from scratch, but you should be comfortable copying code, replacing image URLs, and troubleshooting minor errors. Create a backup and test the slider on a staging site when possible.
Most properly developed WordPress themes can display the slider because it uses standard HTML, CSS, and JavaScript.
Yes. You can use CSS scroll snapping, radio buttons, or CSS animations. However, JavaScript provides more reliable control over arrows, navigation dots, autoplay, keyboard interaction, and accessibility announcements.
There is no universal size for every theme. A 1200 × 675-pixel image is a practical starting point for a wide content slider. Use the dimensions required by your actual layout and keep all images at the same aspect ratio.
Yes. Use the <figcaption> element included in the HTML. The provided CSS displays it over the bottom of the image. Keep the text brief and maintain strong contrast.
Yes. Wrap each image in its own anchor element and use the appropriate destination URL. Make sure the link’s purpose is understandable from the image, caption, or nearby text.
Yes. Duplicate the complete HTML component. The JavaScript initializes each slider independently. Add the CSS and JavaScript only once.
A custom slider is suitable when you need a small, static, carefully controlled component. A plugin is better when non-technical users need to manage slides regularly or when the website requires advanced dynamic features.
This page was last edited on 22 July 2026, at 5:58 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