GestureViewer Props
renderItem
renderItem renders each item in data and receives isActive and setItemDimensions through its third argument: renderItem(item, index, { isActive, setItemDimensions }).
Use isActive for work that should run only on the active item, such as video playback. See renderItem active state (isActive) for behavior and examples.
Call setItemDimensions({ width, height }) after rendered content dimensions become available. See the item dimensions guide for examples and call timing.
getItemDimensions
getItemDimensions(item, index) returns natural dimensions when they are already known. See the item dimensions guide for precedence and fallback behavior.
getItemKey
getItemKey(item, index) returns a stable logical key for runtime dimensions when the same logical item can be recreated as a new object in the same slot. See the item dimensions guide for key requirements.
enableLoop (default: false)
Enables loop mode. When true, navigating next from the last item goes to the first item, and navigating previous from the first item goes to the last item.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
enableLoop={true}
/>
);
}
windowSize (default: 3)
Controls how many internal render-window slots are mounted, including the current item. Values are normalized to an odd number of at least 3; for example, 4 becomes 5.
There is no hard maximum. Large values intentionally mount more renderItem content, so treat them as an explicit memory, render, and image decode cost.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
windowSize={5}
/>
);
}
pageSpacing (default: 0)
Sets horizontal visual space between pages. The page stride is width + pageSpacing, while zoom bounds still use width and height.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
pageSpacing={16}
/>
);
}
autoPlay (default: false)
Enables auto play mode. When true, the viewer will automatically play the next item after the specified interval.
- When
enableLoop is enabled, the viewer will loop back to the first item after the last item.
- When
enableLoop is disabled, the viewer will stop at the last item.
- When there is only one item, auto-play is disabled.
- When zoom or rotate gestures are detected, the auto-play will be paused.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
autoPlay={true}
/>
);
}
autoPlayInterval (default: 3000)
Sets the interval between auto play in milliseconds.
Must be a positive integer. Values below 250ms are clamped to 250ms at runtime.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
autoPlay={true}
autoPlayInterval={3000}
/>
);
}
onSingleTap
Runs when the viewer confirms a single tap. This is useful for toggling viewer chrome such as headers, footers, captions, and action buttons without overlaying another pressable on top of the viewer.
- May resolve slightly later when double-tap zoom is enabled because the viewer waits to confirm it is not a double tap
- Does not fire for swipe, pinch, dismiss, or double-tap zoom gestures
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
const [showControls, setShowControls] = useState(true);
return (
<GestureViewer
data={images}
renderItem={renderImage}
onSingleTap={() => setShowControls((prev) => !prev)}
/>
);
}
initialIndex (default: 0)
Sets the initial index value.
maxZoomScale (default: 2)
Controls the maximum zoom scale multiplier.
GestureViewerProps interface
Go to source
GestureViewerProps
export type GestureViewerItemDimensions = Readonly<{
/** Natural/source content width. Must be finite and greater than zero. */
width: number;
/** Natural/source content height. Must be finite and greater than zero. */
height: number;
}>;
export type GestureViewerItemDimensionsResolver<ItemT> = (
item: ItemT,
index: number,
) => GestureViewerItemDimensions | undefined;
export type GestureViewerItemKey = string | number;
export type GestureViewerItemKeyResolver<ItemT> = (
item: ItemT,
index: number,
) => GestureViewerItemKey;
export type GestureViewerRenderItemInfo = {
/**
* Whether the rendered item is currently active.
* @remarks The current item remains active during a page transition. When the transition finishes on another item, that item becomes active.
*/
readonly isActive: boolean;
/**
* Registers natural/source dimensions for the rendered item after they become available.
* @remarks Call this from an image load or event callback, or from a passive `useEffect` after commit. Do not call it during render or from a descendant layout effect.
*/
readonly setItemDimensions: (dimensions: GestureViewerItemDimensions) => void;
};
export interface GestureViewerProps<ItemT> {
/**
* When you want to efficiently manage multiple `GestureViewer` instances, you can use the `id` prop to use multiple `GestureViewer` components.
* @remarks `GestureViewer` automatically removes instances from memory when components are unmounted, so no manual memory management is required.
* @defaultValue 'default'
*/
id?: string;
/**
* The data to display in the `GestureViewer`.
*/
data: ItemT[];
/**
* The index of the item to display in the `GestureViewer` when the component is mounted.
* @defaultValue 0
*/
initialIndex?: number;
/**
* A callback function that is called when the `GestureViewer` is dismissed.
*/
onDismiss?: () => void;
/**
* A callback function that is called when the dismiss interaction starts.
* @remarks Useful to hide external UI (e.g., headers, buttons) while the dismiss gesture/animation is in progress.
*/
onDismissStart?: () => void;
/**
* A callback function that is called to render the item.
* @param item - The item to render.
* @param index - The index of the item in `data`.
* @param info - Render state for this mounted slot.
*/
renderItem: (item: ItemT, index: number, info: GestureViewerRenderItemInfo) => React.ReactElement;
/**
* A callback function that is called when a single tap is confirmed on the viewer content.
* @remarks
* - The callback runs only after the tap is resolved as a single tap, so it may be slightly delayed when double-tap zoom is enabled.
* - It is not called for swipe, pinch, dismiss, or double-tap zoom gestures.
* - Prefer this callback over overlaying a pressable in `renderContainer` for fullscreen tap handling.
*/
onSingleTap?: (event: GestureViewerSingleTapEvent<ItemT>) => void;
/**
* Returns natural/source dimensions for an item when they are already known.
* @remarks Return `undefined` while dimensions are unavailable. Invalid dimensions fall back to the viewer cell size.
*/
getItemDimensions?: GestureViewerItemDimensionsResolver<ItemT>;
/**
* Returns a stable logical key when the same item can be recreated as a new object in the same slot.
* @remarks Use this when object identity is not stable across rerenders. The key must identify the same rendered content and change when the rendered source or natural dimensions change. Do not return the array index alone. If the item changes position, the viewer falls back to `getItemDimensions` or the viewer cell size until the new slot reports dimensions again.
*/
getItemKey?: GestureViewerItemKeyResolver<ItemT>;
/**
* A callback function that is called to render the container.
* @remarks Useful for composing additional UI (e.g., close button, toolbars) around the viewer.
* Prefer `onSingleTap` for fullscreen tap handling instead of overlaying a pressable over the viewer content.
* The second argument provides control helpers such as `dismiss()` to close the viewer.
*
* @param children - The viewer content to be rendered inside your container.
* @param helpers - Control helpers for the viewer. Currently includes `dismiss()`.
* @returns A React element that wraps and renders the provided `children`.
*/
renderContainer?: (
children: React.ReactElement,
helpers: { dismiss: () => void },
) => React.ReactElement;
/**
* The width of the `GestureViewer`.
* @remarks If you don't set this prop, the width of the `GestureViewer` will be the same as the width of the screen.
* @defaultValue screen width
*/
width?: number;
/**
* The height of the `GestureViewer`.
* @remarks If you don't set this prop, the height of the `GestureViewer` will be the same as the height of the screen.
* @defaultValue screen height
*/
height?: number;
/**
* The style of the backdrop.
*/
backdropStyle?: StyleProp<ViewStyle>;
/**
* The style of the container.
*/
containerStyle?: StyleProp<ViewStyle>;
/**
* Auto play mode.
* @remarks
* - When `true`, the viewer will automatically play the next item after the specified interval.
* - When `enableLoop` is enabled, the viewer will loop back to the first item after the last item.
* - When `enableLoop` is disabled, the viewer will stop at the last item.
* - When there is only one item, auto-play is disabled.
* - When zoom or rotate gestures are detected, the auto-play will be paused.
* @defaultValue false
*/
autoPlay?: boolean;
/**
* Auto play interval.
* @remarks
* - When `autoPlay` is enabled, the viewer advances to the next item after the specified interval (ms).
* - Must be a positive integer. Values below 250ms are clamped to 250ms at runtime.
* @defaultValue 3000
*/
autoPlayInterval?: number;
/**
* Dismiss gesture options.
* @remarks Useful for closing modals with configurable vertical swipe gestures.
*/
dismiss?: {
/**
* When `false`, dismiss gesture is disabled.
* @defaultValue true
*/
enabled?: boolean;
/**
* Controls which vertical swipe direction can trigger `onDismiss`.
* @remarks Use `down` for backward-compatible behavior, `up` for upward-only dismiss, or `both` for either direction.
* @defaultValue 'down'
*/
direction?: GestureViewerDismissDirection;
/**
* `threshold` controls when `onDismiss` is called by applying a threshold value during vertical gestures.
* @defaultValue 80
*/
threshold?: number;
/**
* `resistance` controls the range of vertical movement by applying resistance during dismiss gestures.
* @defaultValue 2
*/
resistance?: number;
/**
* By default, the background `opacity` gradually decreases as you drag in the configured dismiss direction.
* @remarks When `false`, this animation is disabled.
* @defaultValue true
*/
fadeBackdrop?: boolean;
};
/**
* Horizontal swipe gesture options.
* @remarks Controls user-driven left/right page swipe gestures. Controller navigation and autoplay remain available when disabled.
*/
horizontalSwipe?: {
/**
* When `false`, user-driven horizontal page swipe gestures are disabled.
* @defaultValue true
*/
enabled?: boolean;
/**
* Distance threshold as a ratio of viewer width.
* @remarks A page commits when absolute horizontal translation is strictly greater than `width * distanceThresholdRatio`, or when velocity passes `velocityThreshold`. Zero and finite values greater than `1` are accepted; negative and non-finite values fall back to the default.
* @defaultValue 0.25
*/
distanceThresholdRatio?: number;
/**
* Horizontal velocity threshold in points per second.
* @remarks A page commits when absolute horizontal velocity is strictly greater than `velocityThreshold`, or when distance passes `distanceThresholdRatio`. Zero and every finite non-negative value are accepted; negative and non-finite values fall back to the default.
* @defaultValue 800
*/
velocityThreshold?: number;
};
/**
* Only works when zoom is active, allows moving item position when zoomed.
* @remarks When `false`, gesture movement is disabled during zoom.
* @defaultValue true
*/
enablePanWhenZoomed?: boolean;
/**
* Controls two-finger pinch gestures.
* @remarks When `false`, two-finger zoom gestures are disabled.
* @defaultValue true
*/
enablePinchZoom?: boolean;
/**
* Controls double-tap zoom gestures.
* @remarks When `false`, double-tap zoom gestures are disabled.
* @defaultValue true
*/
enableDoubleTapZoom?: boolean;
/**
* Enables infinite loop navigation.
* @defaultValue false
*/
enableLoop?: boolean;
/**
* Number of mounted render-window slots including the current item.
* @remarks Values are normalized to an odd number of at least 3. For example, `4` becomes `5`.
* @defaultValue 3
*/
windowSize?: number;
/**
* Horizontal visual space between pages.
* @remarks Page stride is `width + pageSpacing`; zoom bounds still use `width` and `height`.
* @defaultValue 0
*/
pageSpacing?: number;
/**
* The maximum zoom scale.
* @defaultValue 2
*/
maxZoomScale?: number;
/**
* Trigger-based animation settings
* @remarks You can customize animation duration, easing, and system reduce-motion behavior.
*
* @example
* ```tsx
* <GestureViewer
* triggerAnimation={{
* duration: 250,
* easing: Easing.out(Easing.cubic),
* reduceMotion: 'system',
* onAnimationComplete: () => {
* console.log('Animation complete');
* },
* }}
* />
* ```
*/
triggerAnimation?: TriggerAnimationConfig;
}