React Component Integration

Pagiflow React
Documentation

Official React integration docs for Pagiflow. Learn component props, usePagiflow hook, custom rendering, imperative methods, loop, autoScroll, grid, lazyLoad, thumbnails, sync, responsive and more usage.

30+ Options
12+Methods
0Dependencies
Possibilities

React Integration

Install and use Pagiflow in React with pagiflow/react.

Compatibility: Pagiflow is fully compatible and production-ready for React 16 to the latest releases.
Install
npm i pagiflow
Basic Usage
import { Pagiflow, PagiflowSlide } from 'pagiflow/react';
import 'pagiflow/css';

export default function App() {
  return (
    <Pagiflow id="slider-a" nav loop itemsPerSlide={1}>
      {/* PagiflowSlide is recommended for clarity */}
      <PagiflowSlide className="my-slide">
        <div>Slide 1</div>
      </PagiflowSlide>
      
      {/* You can also use plain elements */}
      <div>Slide 2</div>
      <div>Slide 3</div>
    </Pagiflow>
  );
}
Next.js (SSR) Support

Since Pagiflow interacts with the DOM and window APIs, you must use the 'use client' directive at the top of your component file when using the Next.js App Router.

'use client'; // Required for Pagiflow

import { Pagiflow, PagiflowSlide } from 'pagiflow/react';
import 'pagiflow/css';

export default function NextSlider() {
  return (
    <Pagiflow loop nav itemsPerSlide={3}>
      <PagiflowSlide>Slide 1</PagiflowSlide>
      <PagiflowSlide>Slide 2</PagiflowSlide>
      <PagiflowSlide>Slide 3</PagiflowSlide>
    </Pagiflow>
  );
}
Why 'use client'? Pagiflow needs to measure element dimensions and attach event listeners which are only available on the client side.
Hydration Warnings: In Next.js, browser extensions or theme managers might inject attributes into your <html> or <body> tags, causing React hydration warnings. To prevent this, add suppressHydrationWarning to these tags in your layout.tsx.
usePagiflow Hook

The usePagiflow hook provides a headless way to integrate Pagiflow into your own components, giving you full control over the DOM structure.

import { usePagiflow } from 'pagiflow/react';

function MyCustomSlider() {
  const { sliderRef, instance, next, prev, goTo, play, pause, togglePlayPause, setOptions, reInit, currentIndex } = usePagiflow({
    loop: true,
    itemsPerSlide: 1
  });

  return (
    <div className="custom-container">
      <div className="controls">
        <button onClick={prev}>Previous</button>
        <span>Slide {currentIndex + 1}</span>
        <button onClick={next}>Next</button>
        <button onClick={() => goTo(0)}>First</button>
        <button onClick={play}>Play</button>
        <button onClick={pause}>Pause</button>
        <button onClick={togglePlayPause}>Toggle</button>
        <button onClick={() => setOptions({ gap: 24 }, true)}>Gap 24</button>
        <button onClick={() => reInit({ loop: false })}>ReInit</button>
        <span>Ready: {instance ? 'yes' : 'no'}</span>
      </div>

      <div ref={sliderRef} className="my-slider">
        <div className="slide-1">Slide 1</div>
        <div className="slide-2">Slide 2</div>
      </div>
    </div>
  );
}
Custom Rendering

Use renderNav and renderPagination to inject custom UI that reacts to the slider state.

<Pagiflow
  renderNav={({ next, prev, currentIndex }) => (
    <div className="my-custom-nav">
      <button onClick={prev}>Left</button>
      <button onClick={next}>Right</button>
    </div>
  )}
  renderPagination={({ goTo, currentIndex, total }) => (
    <div className="my-dots">
      {Array.from({ length: total }).map((_, i) => (
        <button 
          key={i} 
          className={currentIndex === i ? 'active' : ''}
          onClick={() => goTo(i)}
        />
      ))}
    </div>
  )}
>
  {/* slides */}
</Pagiflow>
Options
const options = {
  nav: true,
  loop: true,
  itemsPerSlide: 3,
  autoplay: true,
  autoplayDelay: 2500
};

<Pagiflow {...options}>...</Pagiflow>
Methods
import { useRef } from 'react';
import { Pagiflow, type PagiflowHandle } from 'pagiflow/react';

export default function SliderControls() {
  const sliderRef = useRef<PagiflowHandle | null>(null);

  return (
    <>
      <button onClick={() => sliderRef.current?.next()}>Next</button>
      <button onClick={() => sliderRef.current?.prev()}>Prev</button>
      <button onClick={() => sliderRef.current?.goTo(2)}>Go to 3rd</button>
      <button onClick={() => sliderRef.current?.play()}>Play</button>
      <button onClick={() => sliderRef.current?.pause()}>Pause</button>
      <button onClick={() => sliderRef.current?.setOptions({ gap: 24 }, true)}>Update Options</button>
      <button onClick={() => sliderRef.current?.reInit()}>ReInit</button>

      <Pagiflow ref={sliderRef} nav loop itemsPerSlide={1}>
        {/* slides */}
      </Pagiflow>
    </>
  );
}
TypeScript Note: Use the PagiflowHandle type for your useRef to get full autocomplete and type safety for imperative methods like next(), prev(), and play(). If using plain JavaScript (.jsx), you can omit this type.
All-in-One Example

Complete example using both Pagiflow component methods and usePagiflow hook methods.

import { useRef } from 'react';
import {
  Pagiflow,
  PagiflowSlide,
  type PagiflowHandle,
  usePagiflow,
} from 'pagiflow/react';
import 'pagiflow/css';

export default function Example() {
  const sliderRef = useRef<PagiflowHandle | null>(null);

  const {
    sliderRef: customRef,
    instance,
    currentIndex,
    next,
    prev,
    goTo,
    play,
    pause,
    togglePlayPause,
    setOptions,
    reInit,
  } = usePagiflow({
    loop: true,
    nav: true,
    autoplay: true,
    autoplayDelay: 2500,
    itemsPerSlide: 1,
  });

  return (
    <div>
      <h3>Component API + Ref Methods</h3>
      <button onClick={() => sliderRef.current?.prev()}>Prev</button>
      <button onClick={() => sliderRef.current?.next()}>Next</button>
      <button onClick={() => sliderRef.current?.goTo(2)}>Go to 3</button>
      <button onClick={() => sliderRef.current?.resume()}>Resume</button>

      <Pagiflow ref={sliderRef} loop nav paginate onSlideChange={(i) => console.log(i)}>
        <PagiflowSlide>Slide A</PagiflowSlide>
        <PagiflowSlide>Slide B</PagiflowSlide>
        <PagiflowSlide>Slide C</PagiflowSlide>
      </Pagiflow>

      <hr />

      <h3>usePagiflow Hook API</h3>
      <button onClick={prev}>Prev</button>
      <button onClick={next}>Next</button>
      <button onClick={() => goTo(0)}>First</button>
      <button onClick={play}>Play</button>
      <button onClick={pause}>Pause</button>
      <button onClick={togglePlayPause}>Toggle</button>
      <button onClick={() => setOptions({ gap: 24 }, true)}>Gap 24</button>
      <button onClick={() => reInit({ loop: false })}>ReInit</button>

      <p>Current index: {currentIndex}</p>
      <p>Real index (core): {instance?._getRealIndex?.()}</p>

      <div ref={customRef} className="my-slider">
        <div className="slide-1">One</div>
        <div className="slide-2">Two</div>
        <div className="slide-3">Three</div>
      </div>
    </div>
  );
}

Thumbnail Navigation

Show thumbnail strip that syncs with the main slider. Supports top, bottom, left, and right positions.

Option Type Default Description
thumbnails.enabled boolean false Enable thumbnails.
thumbnails.position string 'bottom' 'top', 'bottom', 'left', 'right'.
thumbnails.thumbWidth number|string 80 Width of each thumbnail.
thumbnails.gap number 5 Gap between thumbnails.
thumbnails.sidebarHeight string|number null Height for left/right sidebar mode.
Thumbnails bottom thumbnails.enabled: true
import { Pagiflow, PagiflowSlide } from 'pagiflow/react';
import 'pagiflow/css';

<Pagiflow
  id="gallery-slider"
  loop
  thumbnails={{
    enabled: true,
    position: 'bottom',
    thumbWidth: 90,
    gap: 6
  }}
>
  <PagiflowSlide><img src="/img/1.jpg" alt="1" /></PagiflowSlide>
  <PagiflowSlide><img src="/img/2.jpg" alt="2" /></PagiflowSlide>
  <PagiflowSlide><img src="/img/3.jpg" alt="3" /></PagiflowSlide>
</Pagiflow>

Slider Sync

Connect two slider instances together for synchronized navigation, ideal for galleries, thumbnail previews, and dual-slider layouts.

Option Type Default Description
sync string|instance null CSS selector or Pagiflow instance to sync with.
How it works: Both sliders are linked bidirectionally. Swipe or navigate one and the other follows. Great for thumbnail + main slider combos.
Synchronized Sliders sync: '#nav-slider'
import { Pagiflow, PagiflowSlide } from 'pagiflow/react';

<Pagiflow id="slider-a" loop>
  <PagiflowSlide>Main 1</PagiflowSlide>
  <PagiflowSlide>Main 2</PagiflowSlide>
  <PagiflowSlide>Main 3</PagiflowSlide>
</Pagiflow>

<Pagiflow id="slider-b" nav loop itemsPerSlide={3} sync="#slider-a">
  <PagiflowSlide>Thumb 1</PagiflowSlide>
  <PagiflowSlide>Thumb 2</PagiflowSlide>
  <PagiflowSlide>Thumb 3</PagiflowSlide>
</Pagiflow>

Responsive Breakpoints

Customize slider behavior across different screen sizes by overriding options at specific responsive breakpoints.

Option Type Default Description
responsive object {} Map of breakpoint → options. Applied when window.innerWidth >= breakpoint.
Adaptive Responsive Layout
import { Pagiflow, PagiflowSlide } from 'pagiflow/react';

<Pagiflow
  nav
  paginate
  responsive={{
    0: { itemsPerSlide: 1, gap: 0 },
    576: { itemsPerSlide: 2, gap: 12 },
    768: { itemsPerSlide: 3, gap: 16 },
    1200: { itemsPerSlide: 4, gap: 20, autoplay: true }
  }}
>
  <PagiflowSlide>Slide 1</PagiflowSlide>
  <PagiflowSlide>Slide 2</PagiflowSlide>
  <PagiflowSlide>Slide 3</PagiflowSlide>
  <PagiflowSlide>Slide 4</PagiflowSlide>
</Pagiflow>
Note: Responsive options are deeply merged and re-evaluated on window resize (debounced 120ms).

Events

Hook into slider lifecycle with the onSlideChange prop.

onSlideChange callback

The onSlideChange prop is the most common way to track the active slide in React. It receives the zero-based real index of the active slide.

import { useState } from 'react';
import { Pagiflow, PagiflowSlide } from 'pagiflow/react';

export default function EventDemo() {
  const [active, setActive] = useState(0);

  return (
    <div>
      <div className="status">Current Slide: {active + 1}</div>
      
      <Pagiflow 
        loop 
        nav 
        onSlideChange={(index) => setActive(index)}
      >
        <PagiflowSlide>Slide 1</PagiflowSlide>
        <PagiflowSlide>Slide 2</PagiflowSlide>
        <PagiflowSlide>Slide 3</PagiflowSlide>
      </Pagiflow>
    </div>
  );
}

Methods

All methods return this (chainable) unless noted otherwise.

.next()
Go to the next slide. Respects slidesToScroll and loop. No-ops if already at end without loop.
→ returns this (chainable)
.prev()
Go to the previous slide.
→ returns this (chainable)
.goTo(index, options?)
Jump to slide by zero-based index. Options: { silent: false, instant: false }. silent skips rendering; instant skips animation.
→ returns this
.play()
Resume autoplay. Sets autoplay: true and starts the timer.
→ returns this
.pause()
Pause autoplay or autoScroll animation frame.
→ returns this
.resume()
Resume from paused state. Works for both autoplay and autoScroll.
→ returns this
.togglePlayPause()
Toggle between play and pause.
→ returns this
.setOptions(newOptions, forceRebuild?)
Update options at runtime. Automatically rebuilds if structural options change (itemsPerSlide, gap, fade, etc.).
→ returns this
.html(content?)
Get or set slide HTML. Pass string/array to replace all slides and rebuild. Pass 'dom' to get DOM nodes. No args returns HTML string.
→ string | Node[] | this
.reInit(newOptions?)
Completely reinitialize the slider, optionally with new options. Rebuilds DOM container and re-binds all events.
→ returns this
.destroy()
Tear down the slider completely. Removes container DOM, unbinds all events, cancels timers and RAFs. Shows a loading spinner on the element.
→ void
.onSlideChange(callback)
Set a callback function that fires whenever the active slide changes. Receives the zero-based real index.
→ returns this
._getRealIndex()
Advanced helper that returns the real active index (especially useful when loop is enabled).
→ number

Chaining example

import { useRef } from 'react';
import { Pagiflow, type PagiflowHandle } from 'pagiflow/react';

const sliderRef = useRef<PagiflowHandle | null>(null);

// Chain on underlying core instance
sliderRef.current?.instance
  ?.goTo(2)
  .setOptions({ autoplay: true, autoplayDelay: 2000 })
  .play();

// After 5 seconds, pause
setTimeout(() => {
  sliderRef.current?.instance?.pause();
}, 5000);

All Options Reference

Complete list of all configuration options with types and defaults.

Option Type Default Description
direction string 'horizontal' Slide axis: 'horizontal' or 'vertical'.
itemsPerSlide number 1 Visible slides at once.
slidesToScroll number 1 Steps per navigation click.
gap number 8 Pixels between slides.
height string|number auto Viewport height (Required when using vertical, fade, or thumbnails mode.).
startIndex number 0 Initial slide index.
loop boolean false Infinite loop with DOM clones.
speed number 400 Transition duration (ms).
animate boolean true Enable CSS transitions.
fade boolean false Crossfade instead of slide.
nav boolean false Show built-in prev/next buttons.
navDisabledEnd boolean false Disable (not hide) buttons at ends.
navigation object null External buttons { prev, next }.
prevIcon string '‹' Prev button HTML.
nextIcon string '›' Next button HTML.
prevPosition string|obj null Absolute position for prev button.
nextPosition string|obj null Absolute position for next button.
paginate boolean false Show pagination dots.
paginationPosition string|obj null Custom pagination position.
autoplay boolean false Auto-advance slides.
autoplayDelay number 3000 Delay between auto advances (ms).
pauseOnHover boolean true Pause autoplay on hover.
autoScroll boolean false Continuous marquee scrolling.
autoScrollSpeed number 0.5 Pixels per animation frame.
autoScrollDirection string 'left' 'left' or 'right'.
swipeThreshold number 60 Min swipe distance to trigger change.
grid boolean false Enable grid mode per slide.
gridColumns number 2 Grid column count.
gridFill boolean false Fill last page with recycled items.
thumbnails.enabled boolean false Show thumbnail strip.
thumbnails.position string 'bottom' top / bottom / left / right.
thumbnails.thumbWidth number 80 Thumbnail width in px.
thumbnails.gap number 5 Gap between thumbnails.
thumbnails.sidebarHeight string null Sidebar height for left/right mode.
centerMode boolean false Center active slide with peeking neighbors.
centerPadding number|string 0 Side padding for center mode.
rtl boolean false Right-to-left mode.
keyboard boolean false Arrow key navigation.
lazyLoad boolean false IntersectionObserver image lazy load.
sync string|inst null Selector or instance to sync with.
responsive object {} Breakpoint → options map.
html str|arr null Inject initial slide HTML content during initialization.

Frequently Asked Questions

Common questions about using pagiflow/react.

Install: run npm i pagiflow, import from pagiflow/react, and load pagiflow/css.
Responsive carousel: use responsive breakpoints and override itemsPerSlide, gap, and slidesToScroll.
Controls: use PagiflowHandle methods like next(), prev(), goTo(), play(), pause(), resume().
Headless usage: use usePagiflow to get sliderRef, currentIndex, and control methods.
Sync: give one slider an id and pass selector to sync, for example sync="#slider-a".
Not initializing: confirm pagiflow/css is imported and slides are inside a valid Pagiflow or hook container.
Next.js errors: add 'use client' and initialize only on client-side.
Methods do nothing: ensure ref is attached and not null before calling methods.
Sync not working: verify target id exists and selector matches exactly.
Broken layout after resize: call reInit() or setOptions(newOptions, true).
Run npm i pagiflow, then import from pagiflow/react and styles from pagiflow/css.
Use a ref typed as PagiflowHandle and call sliderRef.current?.next(), prev(), goTo(index). For chain calls, use sliderRef.current?.instance.
Set an id on the first slider, then use sync="#that-id" on the second slider. Example: first id="slider-a", second sync="#slider-a".
Pass a responsive prop object to Pagiflow, with breakpoint keys and option overrides (like itemsPerSlide and gap).
Use the thumbnails prop on Pagiflow, for example { enabled: true, position: 'bottom', thumbWidth: 90, gap: 6 }.
Use onSlideChange prop: <Pagiflow onSlideChange={(index) => setIndex(index)} />. It returns the active real index (0-based).