Introduction
Components
- Accordion
- Action Sheet
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- Badge
- BottomSheet
- Button
- Camera
- Camera Preview
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input
- Input OTP
- Link
- MediaPicker
- Mode Toggle
- Onboarding
- ParallaxScrollView
- Picker
- Popover
- Progress
- Radio
- ScrollView
- SearchBar
- Separator
- Share
- Sheet
- Skeleton
- Spinner
- Switch
- Table
- Tabs
- Text
- Toast
- Toggle
- Video
- View
Charts
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewDemo() {
const card = useThemeColor({}, 'card');
return (
<View
style={{
height: 200,
borderWidth: 1,
borderColor: card,
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView style={{ padding: 16 }}>
{Array.from({ length: 20 }, (_, i) => (
<Text
key={i}
style={{
marginBottom: 8,
padding: 12,
backgroundColor: card,
borderRadius: 6,
}}
>
Scrollable item {i + 1}
</Text>
))}
</ScrollView>
</View>
);
}
Installation
pnpm dlx bna-ui add scroll-view
Usage
import { ScrollView } from '@/components/ui/scroll-view';
<ScrollView>
<Text>Your scrollable content here</Text>
</ScrollView>
Examples
Default
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewDemo() {
const card = useThemeColor({}, 'card');
return (
<View
style={{
height: 200,
borderWidth: 1,
borderColor: card,
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView style={{ padding: 16 }}>
{Array.from({ length: 20 }, (_, i) => (
<Text
key={i}
style={{
marginBottom: 8,
padding: 12,
backgroundColor: card,
borderRadius: 6,
}}
>
Scrollable item {i + 1}
</Text>
))}
</ScrollView>
</View>
);
}
Vertical Scrolling
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewVertical() {
const colors = [
'#ef4444',
'#f97316',
'#eab308',
'#22c55e',
'#3b82f6',
'#8b5cf6',
'#ec4899',
];
return (
<View
style={{
height: 300,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
contentContainerStyle={{ padding: 16, gap: 12 }}
showsVerticalScrollIndicator={true}
>
{Array.from({ length: 15 }, (_, i) => (
<View
key={i}
style={{
height: 80,
backgroundColor: colors[i % colors.length],
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text style={{ color: 'white', fontWeight: 'bold', fontSize: 16 }}>
Card {i + 1}
</Text>
</View>
))}
</ScrollView>
</View>
);
}
Horizontal Scrolling
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewHorizontal() {
const gradients = [
['#ff9a9e', '#fecfef'],
['#a18cd1', '#fbc2eb'],
['#fad0c4', '#ffd1ff'],
['#ffecd2', '#fcb69f'],
['#a8edea', '#fed6e3'],
['#d299c2', '#fef9d7'],
['#89f7fe', '#66a6ff'],
];
return (
<View
style={{
height: 150,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
horizontal={true}
contentContainerStyle={{ padding: 16, gap: 16, alignItems: 'center' }}
showsHorizontalScrollIndicator={true}
>
{Array.from({ length: 10 }, (_, i) => (
<View
key={i}
style={{
width: 120,
height: 100,
backgroundColor: gradients[i % gradients.length][0],
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
}}
>
<Text style={{ color: 'white', fontWeight: 'bold', fontSize: 14 }}>
Item {i + 1}
</Text>
</View>
))}
</ScrollView>
</View>
);
}
Nested ScrollViews
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewNested() {
return (
<View
style={{
height: 300,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView contentContainerStyle={{ padding: 16 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 16 }}>
Vertical Scroll
</Text>
{Array.from({ length: 3 }, (_, sectionIndex) => (
<View key={sectionIndex} style={{ marginBottom: 24 }}>
<Text style={{ fontSize: 16, fontWeight: '600', marginBottom: 12 }}>
Section {sectionIndex + 1}
</Text>
<View
style={{
height: 120,
borderWidth: 1,
borderColor: '#d1d5db',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
horizontal={true}
contentContainerStyle={{
padding: 12,
gap: 12,
alignItems: 'center',
}}
showsHorizontalScrollIndicator={true}
>
{Array.from({ length: 8 }, (_, itemIndex) => (
<View
key={itemIndex}
style={{
width: 80,
height: 80,
backgroundColor: '#3b82f6',
borderRadius: BORDER_RADIUS,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text
style={{
color: 'white',
fontSize: 12,
fontWeight: 'bold',
}}
>
{sectionIndex + 1}.{itemIndex + 1}
</Text>
</View>
))}
</ScrollView>
</View>
</View>
))}
<Text
style={{
padding: 16,
borderRadius: BORDER_RADIUS,
textAlign: 'center',
}}
>
End of scrollable content
</Text>
</ScrollView>
</View>
);
}
With Pull to Refresh
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import { BORDER_RADIUS } from '@/theme/globals';
import React, { useCallback, useState } from 'react';
import { RefreshControl } from 'react-native';
export function ScrollViewRefresh() {
const card = useThemeColor({}, 'card');
const green = useThemeColor({}, 'green');
const [refreshing, setRefreshing] = useState(false);
const [lastRefresh, setLastRefresh] = useState(
new Date().toLocaleTimeString()
);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setRefreshing(false);
setLastRefresh(new Date().toLocaleTimeString());
}, 2000);
}, []);
return (
<View
style={{
height: 300,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
contentContainerStyle={{ padding: 16 }}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
>
<View
style={{
padding: 16,
backgroundColor: green,
borderRadius: BORDER_RADIUS,
marginBottom: 16,
}}
>
<Text style={{ fontWeight: 'bold', color: '#000', marginBottom: 4 }}>
Pull to Refresh
</Text>
<Text style={{ color: '#047857' }}>
Last refreshed: {lastRefresh}
</Text>
</View>
{Array.from({ length: 15 }, (_, i) => (
<View
key={i}
style={{
padding: 16,
backgroundColor: card,
borderRadius: BORDER_RADIUS,
marginBottom: 8,
borderLeftWidth: 4,
borderLeftColor: '#3b82f6',
}}
>
<Text style={{ fontWeight: '600', marginBottom: 4 }}>
News Item {i + 1}
</Text>
<Text style={{ color: '#6b7280' }}>
This is a sample news item that demonstrates the pull-to-refresh
functionality.
</Text>
</View>
))}
</ScrollView>
</View>
);
}
Custom Styling
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';
export function ScrollViewStyled() {
return (
<View style={{ height: 300, borderRadius: 16, overflow: 'hidden' }}>
<ScrollView
style={{
backgroundColor: '#1f2937',
borderRadius: 16,
}}
contentContainerStyle={{
padding: 20,
gap: 16,
}}
showsVerticalScrollIndicator={true}
>
<View
style={{
padding: 20,
backgroundColor: '#374151',
borderRadius: 12,
borderWidth: 1,
borderColor: '#4b5563',
}}
>
<Text
style={{
color: '#f9fafb',
fontSize: 18,
fontWeight: 'bold',
marginBottom: 8,
}}
>
🌙 Dark Theme ScrollView
</Text>
<Text style={{ color: '#d1d5db' }}>
This ScrollView uses custom dark styling with rounded corners and
shadows.
</Text>
</View>
{Array.from({ length: 12 }, (_, i) => (
<View
key={i}
style={{
padding: 16,
backgroundColor: i % 2 === 0 ? '#6366f1' : '#8b5cf6',
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
}}
>
<Text
style={{
color: 'white',
fontWeight: 'bold',
fontSize: 16,
marginBottom: 4,
}}
>
Card {i + 1}
</Text>
<Text style={{ color: '#e5e7eb', opacity: 0.9 }}>
Beautiful custom styled card with gradient-like colors and
shadows.
</Text>
</View>
))}
<View
style={{
padding: 20,
backgroundColor: '#059669',
borderRadius: 12,
alignItems: 'center',
}}
>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
✨ End of styled content
</Text>
</View>
</ScrollView>
</View>
);
}
Scroll Indicators
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewIndicators() {
const card = useThemeColor({}, 'card');
return (
<View style={{ gap: 16 }}>
{/* Vertical with indicators */}
<View>
<Text style={{ fontWeight: 'bold', marginBottom: 8 }}>
With Scroll Indicators
</Text>
<View
style={{
height: 200,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
contentContainerStyle={{ padding: 16, gap: 8 }}
showsVerticalScrollIndicator={true}
indicatorStyle='white'
>
{Array.from({ length: 12 }, (_, i) => (
<Text
key={i}
style={{
padding: 12,
backgroundColor: card,
borderRadius: BORDER_RADIUS,
}}
>
Item {i + 1} - Scroll indicators visible
</Text>
))}
</ScrollView>
</View>
</View>
{/* Horizontal without indicators */}
<View style={{ marginTop: 8 }}>
<Text style={{ fontWeight: 'bold', marginBottom: 8 }}>
Without Scroll Indicators
</Text>
<View
style={{
height: 150,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
horizontal={true}
contentContainerStyle={{
padding: 16,
gap: 12,
alignItems: 'center',
}}
showsHorizontalScrollIndicator={false}
>
{Array.from({ length: 8 }, (_, i) => (
<View
key={i}
style={{
width: 80,
height: 60,
backgroundColor: '#fbbf24',
borderRadius: BORDER_RADIUS,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
{i + 1}
</Text>
</View>
))}
</ScrollView>
</View>
</View>
</View>
);
}
Content Inset
import { ScrollView } from '@/components/ui/scroll-view';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import { BORDER_RADIUS } from '@/theme/globals';
import React from 'react';
export function ScrollViewInset() {
const card = useThemeColor({}, 'card');
return (
<View style={{ gap: 16 }}>
{/* Standard ScrollView */}
<View>
<Text style={{ fontWeight: 'bold', marginBottom: 8 }}>
Standard Content
</Text>
<View
style={{
height: 150,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView contentContainerStyle={{ padding: 16 }}>
{Array.from({ length: 8 }, (_, i) => (
<Text
key={i}
style={{
padding: 12,
marginBottom: 8,
backgroundColor: card,
borderRadius: BORDER_RADIUS,
}}
>
Standard item {i + 1}
</Text>
))}
</ScrollView>
</View>
</View>
{/* ScrollView with content inset */}
<View>
<Text style={{ fontWeight: 'bold', marginBottom: 8 }}>
With Content Inset Adjustments
</Text>
<View
style={{
height: 150,
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: BORDER_RADIUS,
}}
>
<ScrollView
contentContainerStyle={{
paddingTop: 32,
paddingBottom: 32,
paddingHorizontal: 24,
}}
contentInset={{ top: 20, bottom: 20 }}
contentInsetAdjustmentBehavior='automatic'
>
<View
style={{
padding: 16,
backgroundColor: '#ddd6fe',
borderRadius: BORDER_RADIUS,
marginBottom: 16,
borderWidth: 2,
borderColor: '#8b5cf6',
}}
>
<Text style={{ fontWeight: 'bold', color: '#5b21b6' }}>
Header with Inset
</Text>
</View>
{Array.from({ length: 6 }, (_, i) => (
<Text
key={i}
style={{
padding: 12,
marginBottom: 8,
backgroundColor: '#fef3c7',
borderRadius: BORDER_RADIUS,
borderLeftWidth: 3,
borderLeftColor: '#f59e0b',
}}
>
Inset adjusted item {i + 1}
</Text>
))}
<View
style={{
padding: 16,
backgroundColor: '#dcfce7',
borderRadius: BORDER_RADIUS,
marginTop: 8,
borderWidth: 2,
borderColor: '#22c55e',
}}
>
<Text style={{ fontWeight: 'bold', color: '#15803d' }}>
Footer with Inset
</Text>
</View>
</ScrollView>
</View>
</View>
</View>
);
}
API Reference
ScrollView
A wrapper around React Native's ScrollView with enhanced styling capabilities.
Prop | Type | Default | Description |
---|---|---|---|
style | ViewStyle | - | Additional styles to apply to the scroll view. |
contentContainerStyle | ViewStyle | - | Styles applied to the scroll view content container. |
horizontal | boolean | false | When true, the scroll view's children are arranged horizontally. |
showsVerticalScrollIndicator | boolean | true | When true, shows a vertical scroll indicator. |
showsHorizontalScrollIndicator | boolean | true | When true, shows a horizontal scroll indicator. |
scrollEnabled | boolean | true | When false, the content does not scroll. |
bounces | boolean | true | When true, the scroll view bounces when it reaches the end. |
bouncesZoom | boolean | true | When true, gestures can drive zoom past min/max. |
alwaysBounceVertical | boolean | false | When true, the scroll view bounces vertically even when content is smaller. |
alwaysBounceHorizontal | boolean | false | When true, the scroll view bounces horizontally even when content is smaller. |
pagingEnabled | boolean | false | When true, the scroll view stops on multiples of the scroll view's size. |
scrollEventThrottle | number | - | Controls how often the scroll event will be fired while scrolling. |
onScroll | function | - | Fires at most once per frame during scrolling. |
onScrollBeginDrag | function | - | Called when the user begins to drag the scroll view. |
onScrollEndDrag | function | - | Called when the user stops dragging the scroll view. |
onMomentumScrollBegin | function | - | Called when the momentum scroll starts. |
onMomentumScrollEnd | function | - | Called when the momentum scroll ends. |
refreshControl | RefreshControl | - | A RefreshControl component for pull-to-refresh functionality. |
keyboardDismissMode | 'none' | 'on-drag' | 'interactive' | 'none' | Determines when the keyboard is dismissed. |
keyboardShouldPersistTaps | 'always' | 'never' | 'handled' | 'never' | Determines when the keyboard should stay visible after a tap. |
All other props from React Native's ScrollView are also supported.
Accessibility
The ScrollView component maintains React Native's built-in accessibility features:
- Automatically announces scrollable content to screen readers
- Supports gesture-based navigation for users with accessibility needs
- Maintains proper focus management during scrolling
- Compatible with VoiceOver and TalkBack
- Supports dynamic text sizing and high contrast modes