Web component · zero dependencies · GPL-2.0

<flex-slider>

Drop plain images inside an element and it becomes a slider. No jQuery, no stylesheet to load, no icon font, no build step — the markup and styles live in a shadow root, so nothing leaks in or out.

Live

This page is the demo

Everything below is the real component, running on this page. It is not a screenshot, an iframe or a video — the same file the install command fetches. Hover the slider to pause it; drag it on a touch device.

River Valley Coastal Cliffs Resting Pug Waterfall Forest Path
animation="slide" nav pager autoplay interval="4500" pause-on-hover theme="dark" height="380px"

That is the whole markup — one import, then plain images:

<!-- one import; the component is a single file -->
<script type="module" src="flex-slider.js"></script>

<!-- plain images are the whole API -->
<flex-slider animation="slide" nav pager autoplay
             interval="4500" pause-on-hover theme="dark" height="380px">
  <img src="slide-1.jpg" alt="First slide">
  <img src="slide-2.jpg" alt="Second slide">
  <img src="slide-3.jpg" alt="Third slide">
</flex-slider>

Variants

One element, every mode

Three independent instances on this page, each configured by attributes alone. They share no state — paging one leaves the others where they were.

Snowy Peaks Coastline Ocean Sunrise Tall Grass Strawberries Breaching Whale City Bikes Country Road Vintage Camera Lighthouse
Left: animation="fade" pager  ·  Middle: pager thumbs  ·  Right: direction="vertical"

Scripting

Methods, properties and events

The element is the API. Every button drives the slider beside it, and each slide-start and slide-end is written to the panel underneath — the same events you would listen for in your own page.

Foggy Valley Sunset Pier Desert Road Green Hills
listening for slide-start…

Theming

Restyled without touching the component

These two sliders below are driven by CSS custom properties and shadow parts from this page's own stylesheet. The component's internals are untouched — that is the whole point of the shadow boundary.

Sailboat Mountain Lake Pine Forest River Bridge Waterfall Canoe Trip
Left: custom properties in warm tones with a soft focus ring. Right: square arrows and a pill pager, via ::part().
/* custom properties, set on the host */
#theme-warm {
  --fs-accent: #ff9f45;
  --fs-arrow-bg: rgba(255, 159, 69, .92);
  --fs-arrow-fg: #201603;
  --fs-dot: rgba(255, 159, 69, .45);
  --fs-dot-active: #ff9f45;
  --fs-radius: 16px;
}

/* or reach inside by shadow part */
#theme-square::part(arrow-prev),
#theme-square::part(arrow-next) { border-radius: 6px; width: 46px; height: 46px; }
#theme-square::part(pager) { gap: 10px; }

Live updates

Add an image, the slider adapts

The component watches its own children. Appending an image adds a slide, removes nothing, and leaves the current position alone — no re-init call needed. Use the button to grow the gallery.

Strawberries Breaching Whale

Reference

Attributes

AttributeValuesNotes
animationslide, fadeHow slides change. Default slide.
durationmsTransition length. Default 700.
easingany CSS timing functionDefault ease.
autoplaypresentStarts a slideshow on load.
intervalmsTime between slides. Default 5000.
pause-on-hoverpresentPauses while the pointer is over it.
navpresentShows the previous/next arrows.
pagerpresentShows the dot or thumbnail pager.
thumbspresentPager renders thumbnails instead of dots.
slide-show-atindex, 0-basedSlide to start on.
directionhorizontal, verticalAxis the track moves along.
reversepresentAnimates the other way.
rtlpresentMirrors arrows and layout.
swipeon, offDrag and swipe. On by default.
keyboardon, offArrow keys, Home and End. On by default.
smooth-heightpresentAnimates the height between slides.
heightCSS lengthFixed box; images crop with object-fit: cover.
themelight, darkArrow and pager colours.
loopon, offWraps by default; off stops at the ends.
labelstringAccessible name for the region.
prev-label, next-labelstringAccessible names for the arrows.

Methods & events

// methods
slider.next();            slider.prev();
slider.goTo(2);           slider.play();
slider.pause();           slider.refresh();   // re-read the images
slider.reset();           slider.currentIndex = 0;

// properties
slider.currentIndex;      // get and set
slider.slides;            // the original <img> elements

// events — both carry { index, slide, count } and cross the shadow boundary
slider.addEventListener('slide-start', (e) => console.log(e.detail.index));
slider.addEventListener('slide-end',   (e) => console.log(e.detail.slide));

Install

# one file, no dependencies
curl -O https://squidjam.github.io/FlexSlider/flex-slider.js

# or clone the repo and copy it in
git clone https://github.com/squidjam/FlexSlider.git

References

Where to go next

Everything this page demonstrates is written up, testable, or readable in source. The component is small enough to hold in your head — about 600 lines, no dependencies.

No dependencies

No jQuery, no polyfills, no bundler. One module a browser loads directly.

Nothing to configure

Slide widths are measured, not assumed, so any image size and container width works.

Accessible by default

Labelled region, slide positions, named controls, keyboard support and no duplicate announcements.