WebberUI

ClipPath Carousel

A carousel with clip-path reveal transitions in four built-in styles — wipe, iris, diagonal, and box — supporting drag, autoplay, and controlled and uncontrolled modes.

Loading preview…
npx shadcn@latest add https://webberui.com/r/clippath-carousel.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

0.6
<ClippathCarousel />

Installation

npx shadcn@latest add https://webberui.com/r/clippath-carousel.json

Or, once registries are configured in components.json, install it as @webberui/clippath-carousel.

Usage

Every direct child is one slide, and the first item is the initial view. On a change, the entering slide is revealed from its collapsed state to fully open with clip-path, layered over the exiting slide.

import { ClipPathCarousel } from "@/components/ui/clippath-carousel";

<ClipPathCarousel variant="iris">
  <div className="flex h-full items-center justify-center bg-sky-500">One</div>
  <div className="flex h-full items-center justify-center bg-rose-500">Two</div>
  <div className="flex h-full items-center justify-center bg-emerald-500">Three</div>
</ClipPathCarousel>;

Reveal styles

variant offers four single-clip-path transitions:

  • wipe: wipes open from the left or right edge depending on direction
  • iris: a circular iris expanding outward from the center
  • diagonal: a triangle expanding diagonally from the top-left corner (next slide) or the bottom-right corner (previous slide)
  • box: a rectangle expanding from the center in all directions

Autoplay

Set autoPlay and interval; it pauses automatically when the pointer enters, when the keyboard focus enters, or when the tab goes to the background.

<ClipPathCarousel autoPlay interval={3000}>
  {/* ... */}
</ClipPathCarousel>

Programmatic control

Get next() / prev() / goTo() through the ref.

import {
  ClipPathCarousel,
  type ClipPathCarouselHandle,
} from "@/components/ui/clippath-carousel";

const ref = React.useRef<ClipPathCarouselHandle>(null);

<ClipPathCarousel ref={ref}>{/* ... */}</ClipPathCarousel>;
<button onClick={() => ref.current?.next()}>Next</button>;

Controlled mode

Passing index and onIndexChange switches to controlled mode; otherwise use defaultIndex and stay uncontrolled.

const [index, setIndex] = React.useState(0);

<ClipPathCarousel index={index} onIndexChange={setIndex}>
  {/* ... */}
</ClipPathCarousel>;

Props

PropTypeDefaultDescription
childrenReact.ReactNodeEvery direct child is one slide
variant"wipe" | "iris" | "diagonal" | "box""wipe"clip-path reveal style
indexnumberControlled current index
defaultIndexnumber0Initial index in uncontrolled mode
onIndexChange(index: number) => voidFires when the current index changes
loopbooleantrueWhether to loop at the end and the start
durationnumber0.6Duration of the reveal animation (seconds)
autoPlaybooleanfalseWhether to autoplay
intervalnumber4000Autoplay interval (milliseconds)
showArrowsbooleantrueWhether to show the left and right arrows
showIndicatorsbooleantrueWhether to show the indicator dots at the bottom
enableDragbooleantrueWhether drag / swipe switching is allowed
aspectRatiostring"16 / 9"Container aspect ratio (a CSS aspect-ratio value)
slideClassNamestringApplied to each slide's outer element
classNamestringApplied to the outermost container

The ref gives you a ClipPathCarouselHandle: next(), prev(), goTo(index).

How it works

  • During a change both the exiting and the entering slide are rendered: the exiting one rests on the bottom layer while the entering one is revealed over it with clip-path, and the exiting slide unmounts once the animation ends.
  • The transition starts before paint (in a layout effect), avoiding a flash where the whole slide shows outright.
  • A drag (or touch swipe) past the offset or flick velocity threshold switches to the previous or next slide; below the threshold it springs back into place.
  • Both controlled (index + onIndexChange) and uncontrolled (defaultIndex) modes are supported; when the number of children changes, the uncontrolled index is clamped back into the valid range automatically.

Accessibility

  • The container carries role="group" and aria-roledescription="輪播" (Traditional Chinese for "carousel"), and announces the current slide number through an aria-live region.
  • The viewport is focusable, with the left and right arrow keys mapping to previous and next slide; the arrows and the indicator dots are all buttons with an aria-label.
  • When the user has "reduce motion" enabled at the system level, the clip-path reveal and the drag are disabled and switching becomes an instant swap with no large movement.

On this page