Progress Bar in React Native
Progress Bar
~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
Progress bars also have no built-in, cross-platform component in current React Native (the former ProgressBarAndroid/ProgressViewIOS were removed) – the common solution: a View with an animated percentage width.
1. Description
A progress bar consists of two nested Views: an outer one with a fixed width (the "track") and an inner one whose width (as a percentage, or as an animated Animated.Value) represents the current progress.
2. Short example
<View style={{ height: 8, backgroundColor: '#e5e7eb', borderRadius: 4 }}>
<View style={{ width: `${progress}%`, height: '100%', backgroundColor: '#2563eb', borderRadius: 4 }} />
</View>3. Complete project: a file upload simulation
npx create-expo-app progress-bar-demo
cd progress-bar-demoimport { useEffect, useRef } from 'react';
import { Animated, View, StyleSheet } from 'react-native';
function ProgressBar({ percent }) {
const width = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(width, {
toValue: percent,
duration: 300,
useNativeDriver: false, // width can't be animated with the native driver
}).start();
}, [percent]);
return (
<View style={styles.track}>
<Animated.View
style={[
styles.fill,
{ width: width.interpolate({ inputRange: [0, 100], outputRange: ['0%', '100%'] }) },
]}
/>
</View>
);
}
const styles = StyleSheet.create({
track: { height: 10, backgroundColor: '#e5e7eb', borderRadius: 5, overflow: 'hidden' },
fill: { height: '100%', backgroundColor: '#2563eb', borderRadius: 5 },
});
export default ProgressBar;import { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import ProgressBar from './components/ProgressBar';
export default function App() {
const [percent, setPercent] = useState(0);
function simulateUpload() {
setPercent(0);
const interval = setInterval(() => {
setPercent((current) => {
const next = current + 10;
if (next >= 100) clearInterval(interval);
return Math.min(next, 100);
});
}, 200);
}
return (
<View style={styles.container}>
<Text style={styles.label}>Upload: {percent}%</Text>
<ProgressBar percent={percent} />
<View style={styles.button}>
<Button title="Start upload" onPress={simulateUpload} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, paddingTop: 80, paddingHorizontal: 24 },
label: { marginBottom: 8, fontSize: 16 },
button: { marginTop: 20 },
});4. Explanation
useNativeDriver: falseis MANDATORY here –widthis a layout property, and the native driver only supportsopacity/transform.width.interpolate()translates the numeric animated value (0–100) into a percentage STRING ('0%'–'100%'), sincewidthin style expects either a number (pixels) or a percentage string.overflow: 'hidden'on the "track" clips the inner fill at the rounded corners instead of squarely overhanging the edge.setIntervalsimulates a real network upload progress here; in a real app the percentage would typically come from theonUploadProgresscallback of an HTTP library like Axios (see the "Axios" chapter).