Current behavior
react-native-tab-view exposes animationEnabled as a global boolean. This is enough to always animate or never animate tab changes, but it doesn't let a custom tab bar decide that a specific jumpTo call should skip animation.
The underlying native primitive, react-native-pager-view, already supports both behaviors with setPage(index) and setPageWithoutAnimation(index). PagerViewAdapter currently selects between them based on the global animationEnabled prop.
This comes up in apps with heavy top-level tabs and a custom tab bar. A normal tab press should still animate, but if the user rapidly presses between tabs, the second/third press should be able to cancel or skip the in-flight animation and jump immediately to the requested tab. The current public API doesn't provide a way to do that without either:
- setting
animationEnabled: false for all tab presses/programmatic changes, or
- patching
PagerViewAdapter internally to use setPageWithoutAnimation conditionally.
Related prior issues:
Issue #1371 / PR #1388 solved the coarse version of this by adding animationEnabled. This request is for the next layer: per-jump animation policy.
Expected behavior
Would maintainers be open to a patch that allows jumpTo to opt out of animation for a specific tab change, while preserving current behavior by default?
One possible API shape:
type JumpToOptions = {
animated?: boolean;
};
type SceneRendererProps = {
// Backwards compatible: existing `jumpTo(key)` calls keep using `animationEnabled`.
jumpTo: (key: string, options?: JumpToOptions) => void;
};
Then a custom tab bar could do something like:
const isRapidPress = Date.now() - lastTabPressAt.current < 250;
lastTabPressAt.current = Date.now();
jumpTo(route.key, { animated: !isRapidPress });
Internally, PagerViewAdapter could choose between setPage(index) and setPageWithoutAnimation(index) based on options?.animated ?? animationEnabled. The web / pan responder adapter could use the same optional argument to choose whether to animate the jump.
This would avoid app-level patches while keeping the existing global animationEnabled prop as the default policy.
I am happy to put together a PR if this API direction seems acceptable. If maintainers would prefer a different shape, such as an animationEnabled callback or a shouldAnimateJump(fromIndex, toIndex) prop, I'm glad to adapt before implementing.
Reproduction
https://github.com/tian000/react-navigation-tabview-rapid-jump-repro
This is a minimal Expo repro using the latest @react-navigation/native, @react-navigation/material-top-tabs, and react-native-tab-view versions currently published on npm.
The repro renders two sections:
react-native-tab-view: rapid tab presses are detected, but the custom tab bar can only call jumpTo(route.key). The desired jumpTo(route.key, { animated: !isRapidPress }) API is shown in a code comment.
- direct
react-native-pager-view: rapid tab presses call setPageWithoutAnimation; normal tab presses call setPage, demonstrating that the lower-level primitive supports the behavior.
Run:
npm install
npm run android
or:
Then rapidly press Home, Trade, and Explore in both sections.
Platform
Packages
Environment
Verified with the repro app:
| package |
version |
| @react-navigation/native |
7.2.2 |
| @react-navigation/material-top-tabs |
7.4.24 |
| react-native-tab-view |
4.3.0 |
| react-native-pager-view |
6.9.1 |
| react-native |
0.81.5 |
| expo |
54.0.33 |
Current behavior
react-native-tab-viewexposesanimationEnabledas a global boolean. This is enough to always animate or never animate tab changes, but it doesn't let a custom tab bar decide that a specificjumpTocall should skip animation.The underlying native primitive,
react-native-pager-view, already supports both behaviors withsetPage(index)andsetPageWithoutAnimation(index).PagerViewAdaptercurrently selects between them based on the globalanimationEnabledprop.This comes up in apps with heavy top-level tabs and a custom tab bar. A normal tab press should still animate, but if the user rapidly presses between tabs, the second/third press should be able to cancel or skip the in-flight animation and jump immediately to the requested tab. The current public API doesn't provide a way to do that without either:
animationEnabled: falsefor all tab presses/programmatic changes, orPagerViewAdapterinternally to usesetPageWithoutAnimationconditionally.Related prior issues:
Issue #1371 / PR #1388 solved the coarse version of this by adding
animationEnabled. This request is for the next layer: per-jump animation policy.Expected behavior
Would maintainers be open to a patch that allows
jumpToto opt out of animation for a specific tab change, while preserving current behavior by default?One possible API shape:
Then a custom tab bar could do something like:
Internally,
PagerViewAdaptercould choose betweensetPage(index)andsetPageWithoutAnimation(index)based onoptions?.animated ?? animationEnabled. The web / pan responder adapter could use the same optional argument to choose whether to animate the jump.This would avoid app-level patches while keeping the existing global
animationEnabledprop as the default policy.I am happy to put together a PR if this API direction seems acceptable. If maintainers would prefer a different shape, such as an
animationEnabledcallback or ashouldAnimateJump(fromIndex, toIndex)prop, I'm glad to adapt before implementing.Reproduction
https://github.com/tian000/react-navigation-tabview-rapid-jump-repro
This is a minimal Expo repro using the latest
@react-navigation/native,@react-navigation/material-top-tabs, andreact-native-tab-viewversions currently published on npm.The repro renders two sections:
react-native-tab-view: rapid tab presses are detected, but the custom tab bar can only calljumpTo(route.key). The desiredjumpTo(route.key, { animated: !isRapidPress })API is shown in a code comment.react-native-pager-view: rapid tab presses callsetPageWithoutAnimation; normal tab presses callsetPage, demonstrating that the lower-level primitive supports the behavior.Run:
or:
Then rapidly press
Home,Trade, andExplorein both sections.Platform
Packages
Environment
Verified with the repro app: