---
title: "Concepts"
description: "Understand sizing, logical coordinates, looping, and selection in v5"
canonical_url: "https://rn-carousel.dev/concepts"
markdown_url: "https://rn-carousel.dev/concepts.md"
version: "5"
---
# Concepts

v5 separates four ideas that older APIs often mixed together: viewport size, page size, visual position, and settled selection.

## Viewport and page size

The root `style` defines the viewport. Its measured main-axis size is also the default page distance:

```tsx
<Carousel
  style={{ width: 360, height: 200 }}
  data={data}
  renderItem={renderItem}
/>
```

Set `itemSize` only when the page distance differs from the viewport:

```tsx
<Carousel
  style={{ width: 360, height: 200 }}
  itemSize={240}
  data={data}
  renderItem={renderItem}
/>
```

The same `itemSize` prop applies to both orientations. In horizontal mode it is a width; in vertical mode it is a height.

## Raw indices

Every public index refers to the original `data` array:

- `renderItem.index`;
- `defaultIndex`;
- `scrollTo({ index })`;
- `getCurrentIndex()`;
- `onSnapToItem(index)`;
- Pagination press indices.

Loop mode may create internal copies for short arrays, but copy indices never escape the component.

Use `keyExtractor` when identity must survive insertion or reordering. If the selected key disappears, the old numeric index is clamped.

## Logical progress

`progress` is a fractional logical index:

```text
backward  ←  -1   0   1   2  →  forward
```

- item `0` is progress `0`;
- forward movement adds `1` per item;
- backward movement subtracts `1`;
- fractions represent in-flight movement;
- non-loop progress is bounded;
- loop progress is continuous and unbounded.

For loop progress, the settled raw index is the positive modulo of rounded progress by `data.length`. Pagination applies the same nearest-cycle model, so it does not need a `loop` prop or a seam special case.

Progress continuity is guaranteed while data length is stable. A data-length change can rebase the coordinate once without emitting lifecycle events.

## Signed offset

`scrollOffsetValue` exposes the main-axis content translation in pixels:

```text
item 0       item 1         item 2
offset 0  →  -itemSize  →  -2 * itemSize
```

The sign is invariant across horizontal, vertical, LTR, and RTL. Loop offset is continuous and unbounded.

This SharedValue is two-way: an external write moves content. It does not commit selection or fire `onSnapToItem`; use `scrollTo({ index })` to finish at a semantic item. During an active gesture, gesture frames own the offset and may overwrite external writes.

## Relative item progress

Each `renderItem` receives `relativeProgress`:

```text
backward item     selected item     forward item
      -1                0                +1
```

It is a `SharedValue` for animated styles. `itemAnimation` receives the same value as a number on the UI thread.

The coordinate is logical. A custom horizontal `translateX`, however, is a physical React Native transform and must be mirrored by the application for RTL when the effect is directional.

## Live position and settled selection

Visual position changes continuously, while public selection changes only on settle:

- `progress` and `scrollOffsetValue` update during motion;
- `getCurrentIndex()` stays at the previous settled index;
- `onSnapToItem` announces the new settled raw index.

This prevents application state from oscillating between rounded indices during a swipe.

`onScrollStart` marks the start of an accepted movement from gestures, commands, or autoplay. Rejected/no-op commands, direct offset writes, relayout, and data reconciliation do not emit lifecycle events.

## Looping

`loop` defaults to `false`. With `loop`:

- `next` and `prev` preserve their requested logical direction;
- `scrollTo` takes the shortest path and chooses logical forward on a tie;
- progress and offset remain unbounded rather than resetting at cycle boundaries;
- built-in rendering uses bounded derived transforms to avoid precision problems in native view styles.

Autoplay follows the same logical raw-data order. In non-loop mode it stops at the requested direction's boundary.

## Snapping

`snapMode` describes release behavior:

- `"page"`: move at most one logical page per gesture;
- `"nearest"`: settle on the nearest logical page after free movement, fine-tune with `snapMomentum`;
- `"none"`: use free decay, then publish the nearest raw index when motion stops.

`animation` controls page/nearest settle, commands, and autoplay. Free decay and overscroll rebound remain internal physics.

## Render window

`renderWindowSize` limits how many slides are mounted around the current position. Omit it to mount all raw slides.

This is a rendering optimization only. It does not change data, indices, progress, looping, or navigation.

## RTL

Horizontal RTL is detected from `I18nManager.isRTL`. Public APIs stay logical:

- data order is unchanged;
- `next` is still forward;
- progress still increases forward;
- offset still decreases forward;
- a physical right swipe advances in RTL.

Only physical presentation and gesture coordinates are mapped. Vertical carousels are unaffected. Gesture observers receive the original physical RNGH event values.

## Accessibility

Only the current slide is exposed to the accessibility tree. The application owns slide semantics through `renderItem`.

Interactive Pagination dots are buttons with selected state. Without `onPress`, dots are decorative and hidden. External previous/next buttons are a good complement when screen-reader users should move through slides without swiping.

## Adding an example

Use [`itemAnimation`](https://rn-carousel.dev/custom-animations.md) for effects not covered by the built-in layouts.

1. Add a kebab-case demo route under `example/app/app/demos//` by following a nearby example.
2. When it should appear in the documentation, add a self-contained `demo.tsx` and `preview.png` in that route.
3. Run `yarn --cwd example/website gen-pages`; do not edit generated files under `example/website/pages/Examples` directly.
4. Run `yarn --cwd example/website build` to validate the generated page.
5. Run `yarn gif` from the repository root when a GIF asset is needed.
6. Put generated media under `assets` and reference it from the example source.
