React API Reference

Complete reference for @reelkit/react components, props, and methods.

Reel Props

ReelProps

PropTypeDefaultDescription
countnumberrequiredTotal number of items
size[number, number]-Width and height as [width, height]. When omitted, auto-measures via ResizeObserver
itemBuilder(index, indexInRange, size) => ReactElementrequiredFunction to render each slide
direction'vertical' | 'horizontal''vertical'Scroll direction
initialIndexnumber0Starting index
loopbooleanfalseEnable infinite loop
enableWheelbooleanfalseEnable mouse wheel navigation
wheelDebounceMsnumber200Wheel event debounce in ms
enableNavKeysbooleantrueEnable keyboard navigation
onNavKeyPress(increment: -1 | 1) => void-Custom handler for arrow key navigation. Replaces default prev/next behavior.
transitionTransitionTransformFnslideTransitionTransition effect function. Built-in: slideTransition, fadeTransition, flipTransition, cubeTransition, zoomTransition
transitionDurationnumber300Animation duration in ms
enableGesturesbooleantrueEnable touch/mouse drag navigation
swipeDistanceFactornumber0.12Swipe threshold (0-1)
rangeExtractor(index: number, count: number) => number[]defaultRangeExtractorCustom function to determine which indexes are rendered
keyExtractor(index: number) => string-Custom key function for React reconciliation (useful with loop)
apiRefRefObject<ReelApi>-Ref to access API methods
classNamestring-CSS class for the container element
styleCSSProperties-Inline styles for the container element
ariaLabelstring-Accessible label for the carousel region, read by screen readers

Callbacks

PropTypeDescription
afterChange(index, indexInRange) => voidCalled after slide change completes
beforeChange(index, nextIndex, indexInRange) => voidCalled before slide change starts
onSlideDragStart(index) => voidCalled when drag gesture starts
onSlideDragEnd(index) => voidCalled when drag gesture ends
onSlideDragCanceled(index) => voidCalled when drag is canceled

ReelApi Methods

Access slider methods via apiRef:

typescript
const apiRef = useRef<ReelApi>(null);

// Navigation
apiRef.current?.next();
apiRef.current?.prev();
apiRef.current?.goTo(5);           // instant
apiRef.current?.goTo(5, true);     // animated

// Lifecycle
apiRef.current?.adjust();          // recalculate positions
apiRef.current?.observe();         // start observing keyboard
apiRef.current?.unobserve();       // stop observing keyboard
MethodTypeDescription
next()() => voidGo to next slide
prev()() => voidGo to previous slide
goTo(index, animate?)(number, boolean?) => PromiseGo to specific slide
adjust()() => voidRecalculate slide positions
observe()() => voidStart keyboard observation
unobserve()() => voidStop keyboard observation

ReelIndicator Props

ReelIndicatorProps

PropTypeDefaultDescription
countnumberautoTotal number of items. Auto-connected from parent Reel when nested inside one; pass explicitly when used standalone
activenumberautoCurrent active index. Auto-connected from parent Reel when nested inside one; pass explicitly when used standalone
direction'vertical' | 'horizontal''vertical'Indicator orientation
radiusnumber3Dot size in pixels
visiblenumber5Max normal-sized dots visible
gapnumber4Space between dots in pixels
activeColorstring'#fff'Active dot color
inactiveColorstring'rgba(255,255,255,0.5)'Inactive dot color
edgeScalenumber0.5Scale for overflow edge dots
onDotClick(index: number) => void-Callback when a dot is clicked
classNamestring-Custom CSS class
styleCSSProperties-Custom inline styles

Observer Components

Observe

Bridges core signals to React rendering without causing parent re-renders. Only the children function re-executes when subscribed signals change.

tsx
import { Observe } from '@reelkit/react';

<Observe signals={[controller.state.index]}>
  {() => <span>Current: {controller.state.index.value}</span>}
</Observe>
PropTypeDefaultDescription
signalsSubscribable[]requiredSignals to subscribe to. Any of them notifying re-runs the children function — and only that function, never the parent. A different signal on a later render is followed in place of the one it replaced.
children() => ReactElement | nullrequiredRender function, re-executed on each change. Read the signal values inside it; a value read outside is captured once and goes stale.

AnimatedObserve

Subscribes to animated value signals and smoothly interpolates using requestAnimationFrame.

tsx
import { AnimatedObserve } from '@reelkit/react';

<AnimatedObserve signal={controller.state.axisValue}>
  {(value) => (
    <div style={{ transform: `translateY(${value}px)` }} />
  )}
</AnimatedObserve>
PropTypeDefaultDescription
signalSignal<AnimatedValue>requiredSignal emitting { value, duration, done? }. A duration above 0 interpolates from the current value to the new one; 0 jumps straight there.
children(value: number) => ReactElementrequiredRender function receiving the interpolated value for the current frame, committed synchronously so the DOM keeps up with the animation.

Hooks

useBodyLock

Locks body scroll and compensates for scrollbar width shift.

typescript
import { useBodyLock } from '@reelkit/react';

// Lock body scroll when overlay is open
useBodyLock(isOpen);

useOverlayUrlState

OverlayUrlStateOptions

Builds a URL-state controller for an overlay, which you hand to a *UrlOverlay as its controller prop.

See URL State in the React guide for the walkthrough and examples.

OptionTypeDefaultDescription
paramstringrequiredQuery parameter carrying the active slide, e.g. "photo". Read on the first render and fixed for the life of the component — remount (give it a key) to change it.
adapterUrlAdapterHistory APINavigation system to read and write through. Pass a router-backed adapter in a routed app so the router's own location does not go stale. Read on the first render and fixed for the life of the component — remount to change it.
codec{ decode(raw) => Id | null; encode(id) => string }requiredWire format: parameter text ↔ a stable identity, collection-blind. Travels with locator as a matched pair sharing the same Id — spread ...urlIndexKey(() => images.length) for the default ?photo=3 index gallery, or supply your own (base64, slug) so a bookmark survives the gallery being reordered. Read live: the latest render's codec handles the next decode or encode.
locator{ locate(id) => number | null; locateAsync?(id) => Promise<number | null>; identify(index) => id }requiredMaps the identity to a position and owns its own validity: locate (sync), locateAsync (async fallback for a paginated gallery), identify (writes). For a plain index gallery spread ...urlIndexKey(() => images.length) — it supplies this locator plus the matching codec and bounds ?photo=3 against the live count, so a stale ?photo=99 heals out of the URL instead of opening a slide that was never named. A paginated feed or an identity-keyed gallery supplies its own matched codec + locator instead. Read live: the latest render's locator answers the next lookup, and adding or removing locateAsync between renders takes effect on the next miss.

useReactRouterUrlAdapter

A UrlAdapter backed by React Router. Pass it as the adapter option of useOverlayUrlState in a routed app so the router stays the single source of navigation truth — writing history.pushState behind the router leaves its location stale and its next navigation drops the parameter. Writes touch the query only, so the pathname and hash ride along untouched. Every change reports whether the router pushed on the same page, replaced, or stepped through history, so a gallery opened from a <Link> closes with one back step.

Ships from its own subpath, so an app without a router never pulls react-router-dom into its bundle. react-router-dom is an optional peer dependency.

tsx
import { useReactRouterUrlAdapter } from '@reelkit/react/react-router-url-adapter';

const adapter = useReactRouterUrlAdapter();
const photo = useOverlayUrlState({
  param: 'photo',
  adapter,
  ...urlIndexKey(() => images.length),
});

Accessibility

<Reel> renders as role="region" with aria-roledescription="carousel". Set the ariaLabel prop to give the region a screen-reader name. A polite live region announces "Slide N of M" on every slide change without re-rendering the carousel. Inactive slides receive the inert attribute so focus and AT navigation skip them.

<ReelIndicator> renders as role="tablist" with roving tabindex on the dots; arrow keys move focus and Enter or Space activates the slide.

Building a custom modal around <Reel>? captureFocusForReturn, createFocusTrap, and getFocusableElements are re-exported from @reelkit/react for focus return and trap.

Utilities

createDefaultKeyExtractorForLoop

Creates a key extractor that handles duplicate indexes when loop is enabled.

tsx
import { createDefaultKeyExtractorForLoop } from '@reelkit/react';

<Reel
  count={items.length}
  size={size}
  loop
  keyExtractor={createDefaultKeyExtractorForLoop(items.length)}
  itemBuilder={...}
/>