npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rific/scroll-view

v0.6.5

Published

Blur styled scroll system for React Native. Floating headers/footers, keyboard awareness, and scroll-away chrome

Downloads

886

Readme

@rific/scroll-view

Blur-chrome scroll system for React Native. Drop-in replacements for ScrollView, FlatList, and SectionList with floating headers and footers, pull-to-search, keyboard awareness, horizontal paging, and frosted-glass chrome.

Installation

npm install @rific/scroll-view

Peer dependencies

npm install @rific/auto-paper react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-paper react-native-keyboard-controller

The exported Redux slice has no dependency on @reduxjs/toolkit — it works with RTK stores, vanilla Redux, or no Redux at all.

Quick start

Wrap your screen in ScrollViewProvider, add a ScrollViewHeader, then drop in one of the scroll components.

import { ScrollViewProvider, ScrollViewHeader, FlatList } from '@rific/scroll-view'

export default function MyScreen() {
  return (
    <ScrollViewProvider>
      <ScrollViewHeader title="My Screen" backAction={() => router.back()} />
      <FlatList data={items} renderItem={({ item }) => <Row item={item} />} keyExtractor={(item) => item.id} />
    </ScrollViewProvider>
  )
}

For app-wide defaults, wrap your root layout with ScrollViewSettingsProvider.

import { ScrollViewSettingsProvider } from '@rific/scroll-view'

export default function RootLayout({ children }) {
  return (
    <ScrollViewSettingsProvider initialValue={{ snapBack: true }}>
      {children}
    </ScrollViewSettingsProvider>
  )
}

Components

ScrollViewSettingsProvider

App-wide defaults for scroll settings. Wrap your root layout to set global defaults.

| Prop | Type | Description | |------|------|-------------| | children | ReactNode | — | | initialValue | Partial<ScrollViewSettings> | Initial settings applied once on mount | | onChange | (settings: ScrollViewSettings) => void | Called whenever settings change |


ScrollViewProvider

Screen-level provider that owns header/footer state and scroll position. Must wrap ScrollViewHeader, ScrollViewFooter, and the scroll component.

| Prop | Type | Default | Description | |------|------|---------|-------------| | blur | boolean | system | Enable frosted-glass backdrop on header/footer | | fixed | boolean | false | Pin both header and footer (overrides headerFixed/footerFixed) | | footerAboveKeyboard | boolean | false | With a fixed footer, float it above the keyboard instead of letting the keyboard cover it — see Keyboard awareness | | headerFixed | boolean | false | Pin header; overrides settings default | | footerFixed | boolean | false | Pin footer; overrides settings default | | snapBack | boolean | false | Snap header and footer back when scrolling up | | snapBackHeader | boolean | — | Override snapBack for header only | | snapBackFooter | boolean | — | Override snapBack for footer only | | tabBarHeight | number | 0 | Extra bottom inset reserved for a host app's own persistent tab bar (added on top of the safe-area inset, independent of any ScrollViewFooter) |


ScrollViewHeader

Floating header with blur backdrop, title, back action, trailing action, and built-in progress bar. Place it as a direct child of ScrollViewProvider.

| Prop | Type | Default | Description | |------|------|---------|-------------| | title | string | — | Center title text | | caption | string | — | Subtitle below title | | centerContent | ReactNode | — | Replaces title/caption with custom content | | children | ReactNode | — | Left-side content (icon buttons, etc.) | | backAction | () => void | — | Renders a back button and calls this on press | | backActionFixed | boolean | settings | Keep back button visible as header scrolls away | | trailingAction | ReactNode | — | Right-side floating action | | trailingActionFixed | boolean | true | Keep trailing action visible as header scrolls away | | actionSize | number | 48 | Size of floating action buttons | | iconSize | number | actionSize/2 | Icon size inside action buttons | | actionStyle | ViewStyle | — | Style applied to action button backgrounds | | style | ViewStyle | — | Style applied to the header content area | | topInset | boolean | true | Pad for safe area top inset |


ScrollViewFooter

Floating footer with blur backdrop. Place it as a direct child of ScrollViewProvider.

| Prop | Type | Description | |------|------|-------------| | children | ReactNode | Footer content | | style | ViewStyle | Style applied to the inner row |


ScrollView

Drop-in for React Native's ScrollView. Accepts all ScrollViewProps plus:

| Prop | Type | Description | |------|------|-------------| | chipProps | ChipProps | Customize the scroll-to-top chip (label, style, etc.) | | chipThreshold | number | Scroll offset (px) before the chip appears. Default 100 | | footerFixed | boolean | Pin footer for this scroll view; overrides provider | | gesture | GestureType | Compose with an external RNGH gesture | | headerFixed | boolean | Pin header for this scroll view; overrides provider | | keyboardAware | boolean | Add keyboard height to bottom content inset | | onChipPress | () => void | Additional callback fired when the chip is pressed | | onRefresh | () => void | Enables pull-to-refresh | | pullSearchHeight | number | Reserve space above content for PullSearch | | ref | RefObject<RNScrollView> | Forward ref to the underlying scroll view | | refreshing | boolean | Controlled refreshing state |


FlatList

Drop-in for React Native's FlatList. Accepts all FlatListProps<T> plus:

| Prop | Type | Description | |------|------|-------------| | chipProps | ChipProps | Customize the scroll-to-top/start chip (label, style, etc.) | | chipThreshold | number | Scroll offset (px) before the chip appears. Default 100 | | footerFixed | boolean | Pin footer for this list; overrides provider | | gesture | GestureType | Compose with an external RNGH gesture | | headerFixed | boolean | Pin header for this list; overrides provider | | keyboardAware | boolean | Add keyboard height to bottom content inset | | onChipPress | () => void | Additional callback fired when the chip is pressed | | onRefresh | () => Promise<void> \| void | Enables pull-to-refresh | | pullSearchHeight | number | Reserve space above content for PullSearch | | ref | RefObject<RNFlatList> | Forward ref to the underlying list | | renderFilters | ReactNode | Rendered below ListHeaderComponent, above list items |

Performance props are user-overridable with sensible defaults:

| Prop | Default | |------|---------| | initialNumToRender | 20 | | maxToRenderPerBatch | 50 | | windowSize | 100 | | removeClippedSubviews | false | | showsHorizontalScrollIndicator | horizontal | | showsVerticalScrollIndicator | !horizontal |

When horizontal and pagingEnabled are both true and data has more than one item, horizontal dot indicators render automatically.


SectionList

Drop-in for React Native's SectionList. Accepts all SectionListProps<ItemT, SectionT> (except horizontal) plus the same set of library props as FlatList. Custom sticky section headers are supported — pass renderSectionHeader and stickySectionHeadersEnabled and the library renders them via an animated overlay so they properly account for the floating header offset.


CustomList

Wraps any list component that follows the FlatList scroll API (e.g. FlashList). Pass the component via the component prop; all other props are forwarded.

import { FlashList } from '@shopify/flash-list'
import { CustomList } from '@rific/scroll-view'

<CustomList component={FlashList} data={items} renderItem={renderItem} estimatedItemSize={80} />

| Prop | Type | Description | |------|------|-------------| | chipProps | ChipProps | Customize the scroll-to-top chip (label, style, etc.) | | component | ComponentType<P> | The list component to render | | footerFixed | boolean | Pin footer; overrides provider | | gesture | GestureType | Compose with an external RNGH gesture | | headerFixed | boolean | Pin header; overrides provider | | keyboardAware | boolean | Add keyboard height to bottom content inset | | onRefresh | () => Promise<void> \| void | Enables pull-to-refresh | | pullSearchHeight | number | Reserve space above content for PullSearch | | renderFilters | ReactNode | Rendered below ListHeaderComponent, above list items | | scrollRef | RefObject<{ scrollToOffset }> | Forward ref to the underlying list |

The underlying component receives contentInset, contentOffset, onScroll, refreshControl, and scrollEventThrottle — props it must support for the library to function.


ChipProps

Passed via chipProps on any scroll component to customise the floating scroll-to-top chip. Accepts all Chip props from @rific/auto-paper except compact, icon, and onPress (which are managed by the library), plus:

| Prop | Type | Description | |------|------|-------------| | label | ReactNode | Override the default label ("Top" / "Start") | | style | ViewStyle | Merged with the chip's default style |

<FlatList
  chipProps={{ label: 'Back to top', style: { opacity: 0.9 } }}
  data={items}
  renderItem={renderItem}
  keyExtractor={(item) => item.id}
/>

PullSearch

A search bar that lives above the list content and is revealed by pulling down. Use alongside pullSearchHeight on the scroll component.

import { useRef, useState } from 'react'
import { FlatList, PullSearch, type PullSearchHandle } from '@rific/scroll-view'

export default function SearchScreen() {
  const searchRef = useRef<PullSearchHandle>(null)
  const [query, setQuery] = useState('')
  const [searchHeight, setSearchHeight] = useState(0)

  return (
    <ScrollViewProvider>
      <ScrollViewHeader title="Search" />
      <FlatList
        data={filteredItems}
        renderItem={renderItem}
        keyExtractor={(item) => item.id}
        pullSearchHeight={searchHeight}
        ListHeaderComponent={
          <PullSearch
            ref={searchRef}
            value={query}
            onChangeText={setQuery}
            onHeightChange={setSearchHeight}
            placeholder="Search…"
            debounce
          />
        }
      />
    </ScrollViewProvider>
  )
}

| Prop | Type | Description | |------|------|-------------| | onChangeText | (text: string) => void | Called with trimmed search text | | onHeightChange | (height: number) => void | Required — pass the height back as pullSearchHeight | | value | string | Controlled value | | placeholder | string | Placeholder text | | debounce | boolean | Debounce onChangeText by 500ms |

Ref methods: focus(), blur()


Keyboard awareness

Pass keyboardAware to any scroll component (ScrollView, FlatList, SectionList, CustomList) to add the keyboard's height to the bottom content inset, so a focused field near the bottom of the content stays above the keyboard instead of getting hidden behind it.

<ScrollViewProvider>
  <ScrollViewHeader title="Edit profile" />
  <ScrollView keyboardAware>
    <TextInput label="Name" />
    <TextInput label="Bio" multiline />
  </ScrollView>
</ScrollViewProvider>

By default, a fixed ScrollViewFooter doesn't follow the keyboard — it stays pinned to the screen bottom and the keyboard simply covers it. If the footer holds something the user needs while typing (a submit button, say), set footerAboveKeyboard on ScrollViewProvider so the footer floats above the keyboard instead, reachable without dismissing it first:

<ScrollViewProvider footerFixed footerAboveKeyboard>
  <ScrollViewHeader title="Edit profile" />
  <ScrollView keyboardAware>
    <TextInput label="Name" />
    <TextInput label="Bio" multiline />
  </ScrollView>
  <ScrollViewFooter>
    <Button mode="contained" onPress={handleSubmit}>Save</Button>
  </ScrollViewFooter>
</ScrollViewProvider>

footerAboveKeyboard only has an effect when the footer is fixed (footerFixed) — a footer that scrolls away with content has nothing to reserve keyboard space for. Always pair it with keyboardAware: true on any scroll component that could have a focused input while it's visible. Content always reserves space for the current footer height regardless of keyboardAware (so a fixed footer never overlaps it) — and while floating, that height already includes the keyboard, so a list with keyboardAware: false ends up reserving keyboard space anyway, just indirectly through the footer rather than directly. There's no useful configuration where you'd want the footer reachable above the keyboard but not want that same list's own content clear of it too, so don't rely on keyboardAware: false to opt a list out of this while footerAboveKeyboard is on — it won't.

Floating is done by growing the footer's own container rather than translating it, so its BlurView backdrop always stays sealed against the true physical screen bottom — nothing shows through beneath it, including at the keyboard's rounded top corners.

While floating above an open keyboard, the footer also drops its safe-area bottom inset — it's no longer sitting at the physical screen edge, so that padding would just be dead space under its content. As the keyboard closes, the inset ramps back in continuously over the last bit of its travel rather than snapping back once it's fully closed, so the content settles at the safe-area line smoothly instead of dropping to the physical bottom edge and correcting back up.

Keyboard awareness is native-only — useKeyboardInset (and therefore keyboardAware/footerAboveKeyboard) always resolves to 0 height on web.


Hooks

useScrollView

Access scroll state and progress control from anywhere inside a ScrollViewProvider.

const { scrollPosition, scrollHeight, progressing, progress, setProgress, setProgressing } = useScrollView()

| Return | Type | Description | |--------|------|-------------| | scrollPosition | SharedValue<number> | Live scroll offset (Reanimated worklet-safe) | | scrollHeight | number | Visible scroll area height (window minus header/footer) | | progressing | boolean | Whether the header progress bar is visible | | progress | number \| null | Progress bar value (0–1), or null for indeterminate | | setProgress | (p: number \| null) => void | Set progress; pass null for indeterminate | | setProgressing | (b: boolean) => void | Show/hide the progress bar |

// Show an indeterminate progress bar while loading
useEffect(() => {
  setProgressing(true)
  fetchData().finally(() => setProgressing(false))
}, [])

useScrollViewSettings

Read and update scroll settings at runtime from anywhere inside ScrollViewSettingsProvider.

const { settings, set } = useScrollViewSettings()

// Toggle snap-back on the fly
set({ snapBack: true })

useKeyboardInset

Returns the current keyboard height, updating as the keyboard animates in and out. Useful when you need the keyboard height outside of a scroll component.

const keyboardHeight = useKeyboardInset()

Redux integration

If your app uses Redux, you can drive scroll settings from the store instead of (or in addition to) ScrollViewSettingsProvider.

// store.ts
import { scrollViewReducer } from '@rific/scroll-view'

export const store = configureStore({
  reducer: {
    scrollView: scrollViewReducer,
    // ...
  }
})
// Dispatch initial settings (e.g. from a remote config)
store.dispatch(scrollViewActions.initialize({ snapBack: true, headerFixed: false, footerFixed: false, backActionFixed: true }))

Settings reference

ScrollViewSettings defaults:

| Setting | Default | Description | |---------|---------|-------------| | headerFixed | false | Pin header globally | | footerFixed | false | Pin footer globally | | snapBack | false | Snap header and footer back when scrolling up | | snapBackHeader | — | Override snapBack for header only | | snapBackFooter | — | Override snapBack for footer only | | backActionFixed | true | Keep back button visible as header scrolls away |

Settings cascade: ScrollViewSettingsProviderScrollViewProvider → individual scroll component props. More specific values always win.