
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-native-scroll-track
Advanced tools
A customizable, interactive scroll indicator for React Native with drag and tap functionality
✨ A customizable, interactive scroll indicator for React Native. Tap or drag to scroll, with animated thumb and auto-hide behavior.
ScrollView, FlatList, SectionList, FlashList, DraggableFlatList, etc.Try out the scroll track interactively on Expo Snack: 👉 Open in Snack
npm install react-native-scroll-track
npm install react-native-reanimated react-native-gesture-handler
react-native-reanimated/plugin is the last plugin in your babel.config.jsreact-native-reanimatedreact-native-gesture-handler
Important: Make sure react-native-reanimated/plugin is the last plugin in your babel.config.js.Critical: You must wrap your app (or at least the component using ScrollableContainer) with GestureHandlerRootView from react-native-gesture-handler. Without this, you'll get the error:
PanGestureHandler must be used as a descendant of GestureHandlerRootView
Wrap your app with GestureHandlerRootView:
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<YourComponent />
</GestureHandlerRootView>
);
}
import { useScrollTrack } from 'react-native-scroll-track';
const MyScreen = () => {
// These are optional, displayed for illustrative purposes.
const scrollTrackOptions: ScrollTrackOptions = {
inverted: false,
styling: {
thumbColor: 'white',
trackColor: 'steelblue',
},
onPressStart: () => console.log("on press start event"),
onPressEnd: () => console.log("on press end event"),
};
const { scrollProps, ScrollTrack } = useScrollTrack(scrollTrackOptions);
return (
<View style={{ flex: 1 }}>
<FlatList {...scrollProps} data={data} renderItem={renderItem} />
{ScrollTrack}
</View>
);
};
ScrollableContainerThe
ScrollableContainercomponent is deprecated and will be removed in the next major version. UseuseScrollTrackinstead.
<ScrollableContainer>
{({ scrollRef, onScroll, ...props }) => (
<FlatList
ref={scrollRef}
onScroll={onScroll}
{...props}
data={data}
renderItem={renderItem}
/>
)}
</ScrollableContainer>
useScrollTrack Hook Options| Option | Type | Default | Description |
|---|---|---|---|
alwaysVisible | boolean | false | Prevents auto-hide behavior |
disableGestures | boolean | false | Disables tap/drag on scrollbar |
fadeOutDelay | number | 1000 | Delay before fading track (ms) |
hitSlop | number | 36 | Increases the touchable area of the thumb |
inverted | boolean | false | Reverses track direction (chat-style) |
minScrollDistanceToShow | number | 20 | Min scrollable height before track appears |
scrollThrottle | number | 1 | Throttle for scroll events |
styling | object | {} | Styling for track and thumb |
onPressStart | function | Callback when interaction starts | |
onPressEnd | function | Callback when interaction ends | |
onDragStart | function | Callback when thumb drag starts | |
onDragEnd | function | Callback when thumb drag ends | |
externalRef | ref | Supply your own list ref (FlatList, ScrollView, FlashList) |
styling Options| Key | Type | Description |
|---|---|---|
thumbColor | string | Thumb color |
trackColor | string | Track background color |
trackVisible | boolean | Show/hide track background |
trackOpacity | number | Opacity of the track |
thumbOpacity | number | Opacity of the thumb |
trackWidth | number | Width of the track |
thumbHeight | number | Fixed height for the thumb |
thumbBorderRadius | number | Border radius of the thumb |
thumbShadow | object | Shadow style for thumb |
zIndex | number | z-index of the track |
thumbShadow Options| Key | Type | Description |
|---|---|---|
color | string | Shadow color |
opacity | number | Shadow opacity |
radius | number | Blur radius |
offset | object | { width, height } offset |
When inverted is set to true, the scroll track behavior is flipped:
This is useful when working with inverted FlatLists or when you want the scroll track to behave in the opposite direction from the default.
Note: The inverted prop has currently only been tested with FlatLists. Behavior with other scrollable components may vary.
// These are optional, displayed for illustrative purposes.
const scrollTrackOptions: ScrollTrackOptions = {
inverted: true,
};
const { scrollProps, ScrollTrack } = useScrollTrack(scrollTrackOptions);
return (
<View style={{ flex: 1 }}>
<FlatList {...scrollProps} data={data} renderItem={renderItem} />
{ScrollTrack}
</View>
);
};
The onPressStart and onPressEnd callbacks are perfect for implementing haptic feedback to provide tactile responses when users interact with the scroll track. You can use packages like react-native-haptic-feedback to add native haptic responses:
import ReactNativeHapticFeedback from "react-native-haptic-feedback";
import { Platform, Vibration } from "react-native";
// Optional: Configure haptic feedback options
const hapticOptions = {
enableVibrateFallback: true,
ignoreAndroidSystemSettings: false,
};
// Custom vibration patterns for Android
const ANDROID_VIBRATION_PATTERNS: Record<HapticType, number[]> = {
impactLight: [0, 5], // 5ms vibration - extremely subtle
impactMedium: [0, 10], // 10ms vibration - very light
impactHeavy: [0, 20], // 20ms vibration - medium
notificationSuccess: [0, 20, 50, 20], // Success pattern
notificationWarning: [0, 30, 50, 30], // Warning pattern
notificationError: [0, 40, 50, 40], // Error pattern
selection: [0, 5], // Selection - extra light
};
// Define haptic types for different interactions
export type HapticType =
| "impactLight" // Light tap, for subtle UI interactions
| "impactMedium" // Medium tap, for more significant actions
| "impactHeavy" // Strong tap, for important or destructive actions
| "notificationSuccess" // Success notification pattern
| "notificationWarning" // Warning notification pattern
| "notificationError" // Error notification pattern
| "selection"; // Selection feedback pattern
/**
* Triggers haptic feedback using native APIs when available
* @param type The type of haptic feedback to trigger
* @param options Optional configuration for the haptic feedback
*/
export const triggerHapticFeedback = (
type: HapticType = "impactLight",
options = hapticOptions
) => {
try {
if (Platform.OS === "android") {
// Use custom vibration patterns for Android
const pattern = ANDROID_VIBRATION_PATTERNS[type];
Vibration.vibrate(pattern, false);
} else {
// Use standard haptic feedback for iOS
ReactNativeHapticFeedback.trigger(type, {
...options,
ignoreAndroidSystemSettings: false,
});
}
} catch (error) {
console.warn("Haptic feedback not available:", error);
}
};
// Helper functions for common haptic patterns
export const HapticFeedback = {
light: () => triggerHapticFeedback("impactLight"),
medium: () => triggerHapticFeedback("impactMedium"),
heavy: () => triggerHapticFeedback("impactHeavy"),
success: () => triggerHapticFeedback("notificationSuccess"),
warning: () => triggerHapticFeedback("notificationWarning"),
error: () => triggerHapticFeedback("notificationError"),
selection: () => triggerHapticFeedback("selection"),
};
import ReactNativeHapticFeedback from "react-native-haptic-feedback";
import { useScrollTrack } from "react-native-scroll-track";
const MyScreen = () => {
const { scrollProps, ScrollTrack } = useScrollTrack({
styling: { thumbColor: '#007AFF' },
onPressStart: () => triggerHapticFeedback("impactLight"),
onPressEnd: () => triggerHapticFeedback("impactMedium"),
});
return (
<View style={{ flex: 1 }}>
<FlatList {...scrollProps} data={myData} renderItem={renderItem} />
{ScrollTrack}
</View>
);
};
Installation:
npm install react-native-haptic-feedback
Note: Haptic feedback requires additional platform-specific setup. Follow the installation guide for react-native-haptic-feedback to ensure proper functionality across iOS and Android.
Make sure you've wrapped your app with GestureHandlerRootView as shown in the setup section.
Check that your content height is greater than the container height. The scroll track only appears when content is scrollable.
Ensure react-native-reanimated/plugin is the last plugin in your babel.config.js.
The package includes TypeScript definitions. Make sure your TypeScript version is compatible with React Native.
react-native-haptic-feedback correctlyThe component is optimized for performance with:
react-native-reanimatedreact-native-gesture-handlerMIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction...
If you like this package:
Built with ❤️ for the React Native community
FAQs
A customizable, interactive scroll indicator for React Native with drag and tap functionality
We found that react-native-scroll-track demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.