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.
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
enableLoop={true}
/>
);
}
enableSnapMode (default: false)
Enables snap scrolling mode.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
enableSnapMode={true}
/>
);
}
itemSpacing (default: 0)
Sets the spacing between items in pixels. Only applied when enableSnapMode is true.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
enableSnapMode={true}
itemSpacing={16} // 16px spacing between items
/>
);
}
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
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
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)}
/>
);
}
panInertia (default: false)
Adds momentum when a zoomed pan is released. Pass true for defaults, or a configuration object with an explicit enabled field:
<GestureViewer
data={data}
renderItem={renderItem}
panInertia
/>
<GestureViewer
data={data}
renderItem={renderItem}
panInertia={{
enabled: true,
deceleration: 0.9998,
velocityFactor: 1,
rubberBandEffect: true,
rubberBandFactor: 3,
}}
/>
type GestureViewerPanInertiaConfig = {
enabled: boolean;
deceleration?: number;
velocityFactor?: number;
rubberBandEffect?: boolean;
rubberBandFactor?: number;
};
// panInertia?: boolean | GestureViewerPanInertiaConfig
Omitting the prop, passing false, or setting enabled: false preserves release-without-momentum behavior. An empty object is not valid. enablePanWhenZoomed must also be enabled.
Customize only the values you need; omitted fields use these defaults:
deceleration must be finite and strictly between 0 and 1. velocityFactor and rubberBandFactor must be finite and greater than zero. Invalid values fall back to the corresponding defaults. Changes apply to the next release; disabling inertia stops the current animation and removes any remaining overshoot.
Rubber-banding applies to release momentum. Movement settles within the fitted content bounds and does not change pages. Supply getItemDimensions or setItemDimensions for content-aware bounds; otherwise the viewer dimensions are used. A new touch holds the image at its current position, including any overshoot; releasing it returns it to the bounds. Pinch, zoom, rotation, geometry, navigation, and dismissal also interrupt inertia. The viewer manages release velocity, bounds, and system reduced-motion behavior internally; these are not configurable through panInertia.
getItemDimensions
Returns natural/source dimensions for an item when they are already known. Runtime dimensions reported from renderItem with setItemDimensions take precedence. See the item dimensions guide for examples.
getItemKey
Returns a stable logical key for an item when the same content may be recreated as a new object in the same slot. Use it with runtime setItemDimensions values. See the item dimensions guide for details.
initialIndex (default: 0)
Sets the item index the viewer should display. The value is normalized against the current data length: non-finite and negative values become 0, values above the available range become the last index, and empty data resolves to 0.
When initialIndex changes after the viewer is already mounted, the viewer repositions to the normalized index.
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, LC> {
/**
* 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`.
* @remarks
* - Normalized against the current data length: non-finite and negative values become 0, values above range become the last index, and empty data resolves to 0.
* - Prop changes reposition an already-mounted viewer to the normalized index.
* @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 list index of the rendered item.
* @param info - Render state for this list cell.
*/
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;
/**
* Support for any list component like `ScrollView`, `FlatList`, `FlashList` through the `ListComponent` prop.
*/
ListComponent: LC;
/**
* 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 props to pass to the list component.
* @remarks The `listProps` provides **type inference based on the selected list component**, ensuring accurate autocompletion and type safety in your IDE.
*/
listProps?: Partial<ConditionalListProps<ItemT, LC>>;
/**
* 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;
};
/**
* Controls left/right swipe gestures.
* @remarks When `false`, horizontal gestures are disabled.
* @defaultValue true
*/
enableHorizontalSwipe?: boolean;
/**
* 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;
/**
* Adds momentum after releasing a zoomed pan.
* @remarks Requires `enablePanWhenZoomed`. Pass `true` for defaults or an object with `enabled: true` to customize. Respects content bounds and the system reduced-motion setting.
* @defaultValue false
*/
panInertia?:
| boolean
| {
/** Explicitly enables or disables inertia when using a configuration object. */
enabled: boolean;
/**
* Velocity decay rate. Values closer to `1` glide longer.
* @remarks Finite values strictly between `0` and `1`; invalid values use the default.
* @defaultValue 0.9997
*/
deceleration?: number;
/**
* Multiplier applied to the release velocity when calculating movement.
* @remarks Finite values greater than zero; invalid values use the default.
* @defaultValue 0.5
*/
velocityFactor?: number;
/**
* Allows a brief overshoot at the content bounds before returning to the edge.
* @defaultValue true
*/
rubberBandEffect?: boolean;
/**
* Strength of the return from an overshoot. Ignored when `rubberBandEffect` is false.
* @remarks Finite values greater than zero; invalid values use the default.
* @defaultValue 1
*/
rubberBandFactor?: number;
};
/**
* 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;
/**
* Enables snap scrolling mode.
*
* @remarks
* **`false` (default)**: Paging mode (`pagingEnabled: true`)
* - Scrolls by full screen size increments
*
* **`true`**: Snap mode (`snapToInterval` auto-calculated)
* - `snapToInterval` is automatically calculated based on `width` and `itemSpacing` values
* - Use this option when you need item spacing
* @defaultValue false
*
*/
enableSnapMode?: boolean;
/**
* The spacing between items in pixels.
* @remarks Only applied when `enableSnapMode` is `true`.
* @defaultValue 0
*/
itemSpacing?: 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;
}