Next Chapter Begins 🚀Read the full story

useCarousel

Hook that manages carousel scroll snapping, swipe gestures, and page-based navigation.

1
2
3
4
5
basic-demo

Usage#

import { useCarousel } from '@primereact/headless/carousel';
const carousel = useCarousel({ align: 'center' });
 
<div {...carousel.rootProps}>
    <div ref={carousel.contentRef} {...carousel.contentProps}>
        <div {...carousel.getItemProps(0)}></div>
    </div>
    <div {...carousel.indicatorsProps}>
        <button {...carousel.getIndicatorProps(0)}></button>
    </div>
    <button {...carousel.getPrevProps(carousel.state.isPrevDisabled)}></button>
    <button {...carousel.getNextProps(carousel.state.isNextDisabled)}></button>
</div>;

useCarousel wires scroll snapping, swipe gestures, and page tracking together for a content slider. See Primitive for a component-based API.

Features#

  • Scroll-snap navigation, CSS scroll-snap drives the layout, so native momentum, wheel, and touch gestures work out of the box
  • Swipe gestures, pointer-based dragging with auto snap-to-closest when the drag releases
  • Page and slide addressing, navigate by page index or by a specific slide with scrollToPage and scrollToSlide
  • Responsive visibility, slidesPerPage accepts fractional values (e.g. 1.5) to hint at off-screen content
  • Intersection tracking, data-inview updates on each item as it enters or leaves the viewport
  • Configurable layout, orientation, alignment, spacing, auto-size, and loop modes all expose reactive state

Working with callbacks#

onPageChange, controlled navigation#

Pair page with onPageChange when navigation must be driven from parent state, hash routing, or analytics hooks.

const [page, setPage] = React.useState(0);
 
const carousel = useCarousel({
    page,
    onPageChange: (e) => setPage(e.value)
});

Slide-indexed control#

Use slide / onSlideChange for gallery-style carousels where every item is one page.

const [slide, setSlide] = React.useState(0);
 
const carousel = useCarousel({
    slide,
    onSlideChange: (e) => setSlide(e.value)
});

Peek layouts with fractional slides#

Combine slidesPerPage with align: 'start' to show a peek of the next slide, a common mobile pattern.

const carousel = useCarousel({ slidesPerPage: 1.5, align: 'start', spacing: 16 });

Infinite loop navigation#

Enable loop so the prev/next props never disable and navigation wraps at the boundaries.

const carousel = useCarousel({ loop: true });

Rendering custom indicators#

Read state.page and state.snapPoints to draw progress bars, fractions, or dot indicators without extra calculations.

const carousel = useCarousel();
 
<span>
    {carousel.state.page + 1} / {carousel.state.snapPoints.length}
</span>;

Styling with data attributes#

Prop objects include orientation and state-dependent data attributes. contentProps.style also exposes the following CSS custom properties:

VariableDescription
--slides-per-pageNumber of visible slides per page, derived from slidesPerPage.
--spacing-itemsGap between items in pixels, derived from spacing.
--scroll-snap-typeResolved scroll-snap-type value (e.g. x mandatory).
[data-scope='carousel'][data-part='item'] {
    flex-basis: calc(100% / var(--px-slides-per-page) - var(--px-spacing-items) * (var(--px-slides-per-page) - 1) / var(--px-slides-per-page));
}
 
[data-scope='carousel'][data-part='content'][data-orientation='horizontal'] {
    overflow-x: scroll;
}
 
[data-scope='carousel'][data-part='content'][data-orientation='vertical'] {
    flex-direction: column;
    overflow-y: scroll;
}
 
[data-scope='carousel'][data-part='item'][data-inview] {
    opacity: 1;
}
 
[data-scope='carousel'][data-part='indicator'][data-active] {
    background: var(--primary);
}

API#

useCarousel#

NameTypeDefault

Accessibility#

Arrow keys move between slides, Home/End jump to first/last, and Space or Enter pauses autoplay. See Primitive for full WAI-ARIA compliance details.