fluidtabs.
API reference

Tabs.Container

Connect a collapsing header, tab bar, and scrollable pages.

Library source ↗

Type: ContainerProps. View library source.

children

Required

ReactNode

One or more Tabs.Tab elements. Changing tab names, count, or order resets pager and page state.

renderHeader

Optional

(props: HeaderRenderProps) => ReactNode

Collapsible header rendered above the tab bar. Its height is measured automatically.

renderPinnedHeader

Optional

(props: HeaderRenderProps) => ReactNode

Fixed top header. Its content should include any desired padding for topInset.

pinnedHeaderHeight

Optional

number

Height of the pinned header, excluding the safe-area top inset (which is added to the wrapper's height). Omit it to measure the rendered pinned header, including its own top-inset padding, then subtract that inset. An explicit height avoids the first-frame measurement adjustment.

topInset

Optional

number

Top inset reserved by the container. Defaults to the device safe-area inset. Set to 0 to let chrome and content reach the status-bar/notch area, or when an ancestor already handles that inset. Negative values clamp to 0; non-finite values fall back to the device inset.

tabBarHeight

Optional

number

Reserved tab bar height in layout units. Defaults to 56.

initialIndex

Optional

number

Tab to start on. Defaults to 0; rounded and clamped to the available pages. Read once at mount.

index

Optional

number

Controlled active tab: a new external value navigates to that tab. Gestures and taps still move the pager directly and report via onIndexChange — commit that value back to your state to keep the pair in sync. An echoed report acknowledges navigation without restarting it or undoing a newer swipe. Omit it (or pass undefined) for uncontrolled behavior driven by initialIndex, gestures, and the imperative ref.

onIndexChange

Optional

(index: number) => void

Reports the selected navigation target without waiting for animation completion. Gesture notifications reach React asynchronously; obsolete queued notifications may be coalesced during rapid navigation.

scrollToTopOnTabPress

Optional

boolean

Tapping the already-active tab scrolls its list back to the top (the X behavior). Defaults to true; set false to make re-taps inert.

renderTabBar

Optional

(props: TabBarRenderProps) => ReactNode

Custom tab bar; omit for the default pill bar, or return null to hide it. Set tabBarHeight to 0 to remove its reserved space.

containerStyle

Optional

StyleProp<ViewStyle>

Style for the outer container. Give it a bounded width and height.

swipeEnabled

Optional

boolean

Enable horizontal paging gestures. Defaults to true; tab presses and ref navigation still work when false.

headerScrollEnabled

Optional

boolean

Allow vertical dragging on the collapsible header and tab bar. Defaults to true.

swipeActivationDistance

Optional

number

Minimum horizontal travel before the direction rule can select paging. Defaults to 15 dp.

swipeFailDistance

Optional

number

Minimum vertical travel before a clearly vertical drag yields to scrolling. Defaults to 10 dp.

swipeDirectionRatio

Optional

number

Required dominance of one axis over the other. Defaults to 1.4; values below 1 are clamped to 1. Ambiguous diagonals yield to scrolling after twice the larger activation distance. Direction locks until release.

momentumSwipeFailDistance

Optional · Deprecated

number

See the usage guides for how this value fits into a screen.

Ignored. Direction recognition now uses the same ratio and distances during momentum as at rest. Use swipeDirectionRatio, swipeActivationDistance and swipeFailDistance to tune recognition.

swipeGestureTopInset

Optional

SwipeGestureTopInset

Top area where the horizontal pager pan should not activate. 'auto' (default) follows the currently visible pinned header, safe-area inset, collapsible header, and tab bar. A number reserves a fixed area instead. Pass 0 to allow pager swipes from the full page height.

springConfig

Optional

SpringConfig

Spring for gesture releases. Programmatic navigation uses a timing animation.

damping

number

Spring damping. Defaults to 30.

stiffness

number

Spring stiffness. Defaults to 200.

mass

number

Spring mass. Defaults to 1.

overshootClamping

boolean

Stop the spring at its target without overshooting. Defaults to true.

minPageContentHeight

Optional

number

Minimum content height per page, so short or empty pages can still scroll far enough to hold the fully-collapsed chrome. Defaults to the measured container height plus the measured header height. Longer content can scroll further. Per-list minContentHeight overrides it for one page.

estimatedHeaderHeight

Optional

number

Optional first-frame estimate for the collapsible header height. The real measured height still wins after layout, but this keeps list spacers from starting at 0 and jumping on the first scroll.

lazy

Optional

boolean

Lazily mount tab pages as they are visited. Mounted tabs stay mounted so scroll state is preserved when returning to a tab. Defaults to false.

lazyPreloadDistance

Optional

number

Number of neighboring tabs to mount before they are visited when lazy is enabled. Defaults to 1 so adjacent swipe targets are ready.

pullDownBehavior

Optional

PullDownBehavior

How the page behaves on pull-down at the top.

  • 'stretch' — the whole page rides down with the pull: the collapsible header and tab bar translate down while the pinned header stays put, revealing the refresh indicator near the top of the screen. On iOS this rides the native bounce with the native RefreshControl. Android has no native bounce, so the Container drives the pull itself: the native SwipeRefreshLayout is suppressed and a built-in indicator is shown instead — your refreshControl element's refreshing and onRefresh still drive it, no API change.
  • 'static' (default) — chrome stays put; the native RefreshControl appears between the header chrome and the list content on both platforms (progressViewOffset is injected automatically; pass your own to override). iOS stretch mode offsets its native indicator below the pinned header and top inset. Android stretch uses a built-in indicator and does not apply native indicator styling props.

The web wrappers do not implement native pull-to-refresh gestures.

Header render values

Both renderHeader and renderPinnedHeader receive HeaderRenderProps. Read shared values in animated styles or reactions to respond to scrolling.

HeaderRenderProps.scrollY

SharedValue<number>

Active page's scroll position; negative values represent overscroll.

HeaderRenderProps.headerHeight

SharedValue<number>

Collapsible header height, initially estimated and then measured.

HeaderRenderProps.topInset

number

Reserved top inset. Apply it as padding inside the pinned header if needed.

HeaderRenderProps.pinnedHeaderHeight

number

Pinned header height, excluding topInset.