Slider

Show images or any content one slide at a time, or several at once, with smooth effects, swipe, keyboard support and accessible controls.

About

The Slider shows a set of slides one after another. Each slide is a Slide component that holds an image or any content. The Slider can play by itself, loop, follow a swipe or a mouse drag, show several slides at once, and change slides with effects like fade, zoom, flip and cube. It works in right-to-left pages and respects the user's reduced motion setting.

Example

Put Slide components inside a Slider. By default the Slider plays by itself and shows arrows, dots, a timer bar and a pause button.

Image Slider

Give a Slide an image with src and alt.

Image slide demo image
Svelte
<Slider>
  <Slide src="..." alt="..." />
  <Slide src="..." alt="..." />
  <Slide src="..." alt="..." />
</Slider>

Custom Content Slider

A Slide can hold any content instead of an image. Use class to style the slide itself.

Build Faster

Modern, responsive and customizable components.

Svelte
<Slider>
  <Slide class="h-72 flex-col gap-2 bg-yellow-200">
    <h3>Build Faster</h3>
    <p>...</p>
  </Slide>
  <Slide class="h-72 flex-col gap-2 bg-rose-200"> ... </Slide>
  <Slide class="h-72 flex-col gap-2 bg-teal-200"> ... </Slide>
</Slider>

Linked Slides

Add href to make the whole slide a link. The link is named by the image alt or by the slide content, so write an alt that describes where it goes. A drag or swipe never follows the link. Don't put other links or buttons inside a linked slide.

Shop the summer collection
Svelte
<Slider>
  <Slide href="/summer" src="..." alt="Shop the summer collection" />
  <Slide href="/new" src="..." alt="See the new arrivals" />
</Slider>

Controls & Indicator

The controls prop shows the previous and next buttons, and the indicator prop shows a dot for each slide. Both are true by default; set them to false to hide them. When the slider doesn't loop, the previous button is disabled on the first slide and the next button on the last.

Image slide demo image
Svelte
<Slider indicator={false} controls={false}> ... </Slider>

Without controls, users can still change slides by swiping or with the keyboard.

Custom Controls Icon

Replace the arrow icons of the previous and next buttons with the prevButton and nextButton snippets. The buttons keep their accessible names.

Image slide demo image
Svelte
<Slider>
  <!-- Previous button -->
  {#snippet prevButton()}
    <Svg size={2} class="opacity-50">
      <path fill-rule="evenodd" d="M1 8a7 7 0 1 ... 1 .708.708L5.707 7.5z"/>
    </Svg>
  {/snippet}
  <!-- Next button -->
  {#snippet nextButton()}
    <Svg size={2} class="opacity-50">
      <path fill-rule="evenodd" d="M1 8a7 7 0 1 ... 1 0-.708.708L10.293 7.5z"/>
    </Svg>
  {/snippet}

  <Slide src="..." alt="..." />
  <Slide src="..." alt="..." />
  <Slide src="..." alt="..." />
</Slider>

Auto Play & Stop on Hover

The autoPlay prop moves to the next slide by itself. It is true by default. At the last slide of a slider that doesn't loop, it goes back to the first slide.

Auto play pauses while the mouse is over the slider and continues from where it stopped when the mouse leaves. Set stopOnHover to false to keep it running. Auto play also pauses while keyboard focus is inside the slider, while the slider is scrolled out of view and while the browser tab is hidden. Moving to another slide restarts the timer.

Image slide demo image
Svelte
<Slider stopOnHover={false}> ... </Slider>

Pause Button

When auto play is on, a pause button in the bottom corner stops and restarts it. Content that moves by itself needs a way to stop it, so keep this button unless you give users another one. Hide it with pauseButton={false}.

Use bind:paused to read the paused state or to pause the slider from your own control.

Image slide demo image
Svelte
<script>
  let paused = $state(false)
</script>

<button onclick={() => paused = !paused}>{paused ? "Play" : "Pause"}</button>

<Slider bind:paused pauseButton={false}> ... </Slider>

Timer & Fraction

The timer prop shows a progress bar at the top that fills up until the next slide. It is true by default and only shows while auto play is on. The fraction prop shows a counter like 2 / 5 in the top corner. It is false by default. Use either one, both, or neither.

Image slide demo image
Svelte
<Slider timer={false} fraction> ... </Slider>

Slide Duration

The slideDuration prop sets how long each slide stays, in milliseconds, before auto play moves to the next one. Default is 5000 (5 seconds).

Image slide demo image
Svelte
<Slider slideDuration={2000}> ... </Slider>

In the example each slide stays for 2 seconds.

Transition Duration

The transitionDuration prop sets how long the move between two slides takes, in milliseconds. Default is 750. Set it to 0 to change slides instantly.

Image slide demo image
Svelte
<Slider transitionDuration={2000}> ... </Slider>

In the example each move takes 2 seconds.

Active Slide

The activeSlide prop sets the slide shown first, starting from 1. Default is 1. A number above the slide count shows the last slide.

activeSlide is bindable: bind:activeSlide follows the current slide, and changing the bound value moves the slider. The onchange callback runs with the new slide number every time the slide changes.

Current slide: 2
Image slide demo image
Svelte
<script>
  let active = $state(2)
</script>

<button onclick={() => active = 1}>Show 1</button>

<Slider bind:activeSlide={active} onchange={(slide) => console.log(slide)}> ... </Slider>

Loop

By default the slider loops: after the last slide comes the first one, without a jump back. Set loop to false to stop at the first and last slides.

Image slide demo image
Svelte
<Slider loop={false}> ... </Slider>

Effects

The effect prop sets how one slide changes to the next: "slide" (default), "fade", "zoom", "flip" or "cube". Every effect follows a swipe or drag step by step. perView, gap, peek and centered only work with "slide".

Fade

The slides cross-fade.

Image slide demo image
Svelte
<Slider effect="fade"> ... </Slider>

Zoom

The new slide grows in while the old one grows past its size and fades out.

Image slide demo image
Svelte
<Slider effect="zoom"> ... </Slider>

Flip

The slide flips like a card, side to side. In a vertical slider it flips top to bottom.

Image slide demo image
Svelte
<Slider effect="flip"> ... </Slider>

Cube

The slides are the sides of a turning cube. In a vertical slider the cube turns up and down.

Image slide demo image
Svelte
<Slider effect="cube" class="bg-gray-900"> ... </Slider>

Ken Burns

The kenBurns prop slowly zooms and pans each image while its slide is shown, each slide in a different direction. It works with every effect and only on image slides (a Slide with src).

Image slide demo image
Svelte
<Slider effect="fade" kenBurns transitionDuration={1500}> ... </Slider>

Parallax

Image Parallax

The parallax prop moves the image of each slide slower than the slide, so it lags behind. parallax alone uses 0.5; set a number from 0 to 1 for less or more. At 1 the image stays still and the slide edge wipes across it. It only works with the "slide" effect and on image slides.

Image slide demo image
Svelte
<Slider parallax> ... </Slider>
<Slider parallax={1}> ... </Slider>

Layer Parallax

Elements inside any slide can move at their own speed while the slide changes. Add these attributes to an element:

  • data-parallax: how far the element moves, as a part of the slide size. A higher number moves it more; a negative number moves it ahead of the slide.
  • data-parallax-opacity: the element's opacity when its slide is out of view, so 0 fades it in as the slide arrives.
  • data-parallax-scale: the element's scale when its slide is out of view, so 0.5 grows it in.

Layers work with every effect.

Layer slide 1

Each layer moves at its own speed.

Svelte
<Slider>
  <Slide class="h-72 bg-yellow-200">
    <h3 data-parallax="0.6">Layer slide 1</h3>
    <p data-parallax="0.3" data-parallax-opacity="0">Each layer moves at its own speed.</p>
    <button data-parallax-scale="0.5" data-parallax-opacity="0">Read more</button>
  </Slide>
  ...
</Slider>

Vertical Slider

Set direction="vertical" to move the slides up and down. A vertical slider needs a height; it is h-96 by default and you can change it with class. The Up and Down arrow keys change slides, the controls sit at the top and bottom, and the dots move to the side.

Image slide demo image
Svelte
<Slider direction="vertical" class="h-80"> ... </Slider>

Multiple Slides

Slides Per View

The perView prop shows several slides at once, like a carousel, and gap sets the space between them. gap takes a number of pixels or any CSS length like "1rem". The slider still moves one slide at a time.

Card 1
Card 2
Card 3
Svelte
<Slider perView={3} gap={16}> ... </Slider>

Responsive

perView, gap and peek also take a value per screen size, using the Tailwind breakpoints: base, sm, md, lg, xl and 2xl. The largest matching screen size is used. Resize the window to see it change.

Card 1
Svelte
<Slider perView={{ base: 1, sm: 2, lg: 3 }} gap={{ base: 8, lg: 20 }}> ... </Slider>

The screen size is known only in the browser, so a page rendered on the server starts with the base value.

Peek & Centered

Peek

The peek prop shows a part of the previous and next slides at the edges, so users can see there is more. It takes a number of pixels or any CSS length. The peeking slides can't be reached with the keyboard until they move into view.

Image slide demo image
Svelte
<Slider peek={{ base: 24, md: 80 }} gap={16}> ... </Slider>

Centered

The centered prop places the active slide in the middle, with the other slides on both sides. It is useful with perView. Without loop, the first and last slides are centered too, with empty space beside them.

Card 1
Card 2
Svelte
<Slider centered perView={3} gap={12}> ... </Slider>

To loop, a slider needs more slides than it can show at once: at least perView + 1, or perView + 3 with peek. With fewer slides it stops at the ends.

Thumbnails

The thumbnails prop shows a strip of small images under the slider. Clicking one opens its slide, and the active thumbnail stays in the middle of the strip. A thumbnail uses the slide's src; set the thumbnail prop on a Slide to use another image, or for a content slide. A slide without an image shows its number. You can hide the dots with indicator={false}.

Image slide demo image 1
Svelte
<Slider thumbnails indicator={false}>
  <Slide src="..." alt="..." />
  <Slide src="..." alt="..." thumbnail="small-image.jpg" />
  <Slide thumbnail="preview.jpg"> <!-- Custom content --> </Slide>
</Slider>

Swipe & Mousewheel

Users can swipe on touch screens and drag with the mouse. The slides follow the finger, and a move of a small part of a slide is enough to change it. A drag never clicks a link or button inside the slide. Turn it off with swipe={false}.

The mousewheel prop changes slides with the mouse wheel or a trackpad, one slide per gesture. It is false by default because it takes over page scrolling while the pointer is on the slider. Without loop, the page scrolls normally again at the first and last slides.

Image slide demo image
Svelte
<Slider direction="vertical" class="h-80" mousewheel loop={false}> ... </Slider>

Hero & Background Slider

Hero Slider

The overlay snippet holds content that stays on top while the slides change, like a title and a button over a set of images. Links, buttons and fields in the overlay can be clicked, and dragging on the rest of it still swipes the slides. Set a height with class for a full-height hero.

Build faster with theui

Get started
Svelte
<Slider class="h-[80vh]" effect="fade" kenBurns controls={false} ariaLabel="Hero images">
  {#snippet overlay()}
    <div class="size-full flex flex-col items-center justify-center gap-4 bg-black/30 text-white">
      <h1>Build faster with theui</h1>
      <a href="/docs">Get started</a>
    </div>
  {/snippet}
  <Slide src="..." alt="" />
  <Slide src="..." alt="" />
</Slider>

Page Background

To use the slider as the background of the whole page, fix it behind the content and hide the parts users can't reach. The page content covers the slider's own pause button, so hide it and place your own pause button with bind:paused. Images that are only decoration can have an empty alt.

Svelte
<script>
  let paused = $state(false)
</script>

<Slider
  class="fixed inset-0 -z-10 h-auto"
  effect="fade"
  kenBurns
  controls={false}
  indicator={false}
  timer={false}
  swipe={false}
  pauseButton={false}
  bind:paused
  ariaLabel="Page background"
>
  <Slide src="..." alt="" />
  <Slide src="..." alt="" />
</Slider>

<button onclick={() => paused = !paused}>{paused ? "Play" : "Pause"} background</button>

Right to Left

In a right-to-left page (dir="rtl"), the slider moves the other way: the next slide comes from the left, the controls swap sides, dragging follows the finger, and the Left arrow key goes to the next slide. The direction is read when the slider loads.

Customization

Use class on the Slider for the whole slider and on a Slide for that slide. Other attributes, like id, go on the same element. These props style the other parts:

  • slideClasses: classes for every slide, like padding, background or rounded corners.
  • controlButtonClasses: classes for the previous and next buttons, to change their size, color or position.
  • indicatorContainerClasses: classes for the container of the dots, to change their position or spacing.
  • indicatorClasses: classes for every dot, to change its shape, size or color.
  • indicatorActiveClasses: classes added to the dot of the active slide.
  • thumbnailContainerClasses: classes for the thumbnail strip.
  • thumbnailClasses: classes for every thumbnail, like its size.
  • thumbnailActiveClasses: classes added to the thumbnail of the active slide.
  • timerClasses: classes for the timer bar, like its height or color.
  • fractionClasses: classes for the fraction counter, like its position or colors.
  • pauseButtonClasses: classes for the pause button.
  • overlayClasses: classes for the container of the overlay snippet.

Your classes are merged with the default classes, so a class you set replaces the default one it conflicts with.

Accessibility

The Slider follows the WAI-ARIA carousel pattern, so it works with the keyboard and with screen readers.

Keyboard Navigation

When focus is on a control, a dot, a thumbnail or content inside the slider:

  • ← and → move to the previous and next slide (↑ and ↓ in a vertical slider).
  • Home and End move to the first and last slide.
  • Tab moves through the pause button, the controls, the dots and the content of the slides in view.
  • Enter or Space press the focused button.

When a key moves away from a slide that had focus, focus moves to the new slide.

Screen Reader Support

  • The slider is announced as a carousel, named by the ariaLabel prop (default "Slider"). Give it a name that describes the slides.
  • Each slide is announced as a slide with its position, like "2 of 5".
  • Slides that are not in view are hidden from screen readers and can't be reached with Tab.
  • Slide changes are announced when the user changes the slide, but not during auto play, so they don't interrupt.
  • The previous, next, pause, dot and thumbnail buttons have accessible names, and the active dot and thumbnail are marked as current.

Motion

  • Auto play stops while keyboard focus is inside the slider, and the pause button stops it for good.
  • For users who turn on reduced motion in their system, slides change instantly and auto play, the timer, the pause button and the Ken Burns zoom are turned off.

Configuration

Slider

Slide