We are going to implement the Bill Splitter App using React Native. Bill Splitter App is a mobile application that helps us divide expenses and bills among a group of people. For example, when we are dining at a restaurant with friends, going on a trip, or sharing household expenses with roommates.
To give you a better idea of what we’re going to create, let’s watch a demo video.
Demo Video
Playground
Note: This Section is to interact with the app which you are going to build.
Prerequisites:
Approach:
- Bill Splitter App is a mobile application that helps us split expenses and bills among a group of people.
- It takes the name and money spent by each individual.
- Then this App calculates the money equally among all.
- We also included a calculate button in the app, so when the button is clicked, it shows the Name from whom to take money or whom to give money.
- We also added a reset button in the app to reset the data.
Step-by-Step Implementation
Step 1: Create a React Native Project
Now, create a project with the following command.
npx create-expo-app app-name --template
Note: Replace the app-name with your app name for example : react-native-demo-app
Next, you might be asked to choose a template. Select one based on your preference as shown in the image below. I am selecting the blank template because it will generate a minimal app that is as clean as an empty canvas in JavaScript.

It completes the project creation and displays a message: "Your Project is ready!" as shown in the image below.

Now go into your project folder, i.e., react-native-demo
cd app-nameProject Structure:

Step 2: Run Application
Start the server by using the following command.
npx expo startThen, the application will display a QR code.
- For the Android users,
- For the Android Emulator, press " a" as mentioned in the image below.
- For the Physical Device, download the " Expo Go " app from the Play Store. Open the app, and you will see a button labeled " Scan QR Code. " Click that button and scan the QR code; it will automatically build the Android app on your device.
- For iOS users, simply scan the QR code using the Camera app.
- If you're using a web browser, it will provide a local host link that you can use as mentioned in the image below.

Step 3: Start Coding
Example:
- Emulator will open after this command, and after opening of emulator, you are ready to work in VS Code to write the code.
- Open the file and simply paste the source code
import React, { useState } from 'react';
import {
View, Text, TextInput,
TouchableOpacity, StyleSheet,
ScrollView
} from 'react-native';
const BillSplitter = () => {
const [participants, setParticipants] =
useState(
[
{
name: '',
amount: ''
}
]);
const [settleTransactions, setSettleTransactions] = useState([]);
const addParticipant = () => {
setParticipants(
[...participants,
{
name: '',
amount: ''
}]);
};
const removeParticipant = (index) => {
const updatedParticipants = [...participants];
updatedParticipants.splice(index, 1);
setParticipants(updatedParticipants);
};
const calculateSplit = () => {
const totalExpense = participants.reduce(
(total, participant) =>
total + parseFloat(participant.amount || 0),
0
);
const splitAmount =
totalExpense / participants.length;
const calculatedResults =
participants.map((participant) => {
const amount =
(splitAmount - parseFloat(participant.amount)).toFixed(2);
return {
name: participant.name,
amount: parseFloat(amount),
};
});
const settleTransactions = [];
let positiveBalances =
calculatedResults.filter(
(result) =>
result.amount > 0);
let negativeBalances =
calculatedResults.filter(
(result) =>
result.amount < 0);
while (positiveBalances.length > 0 &&
negativeBalances.length > 0) {
const payer = positiveBalances[0];
const payee = negativeBalances[0];
const settledAmount =
Math.min(
Math.abs(payer.amount),
Math.abs(payee.amount));
settleTransactions.push({
payer: payer.name,
payee: payee.name,
amount: settledAmount.toFixed(2),
});
payer.amount -= settledAmount;
payee.amount += settledAmount;
if (Math.abs(payer.amount) < 0.005) {
positiveBalances.shift();
}
if (Math.abs(payee.amount) < 0.005) {
negativeBalances.shift();
}
}
setSettleTransactions(settleTransactions);
};
const resetApp = () => {
setParticipants([{ name: '', amount: '' }]);
setSettleTransactions([]);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Bill Splitter</Text>
<ScrollView style={styles.participantList}>
{participants.map((participant, index) => (
<View key={index} style={styles.participantItem}>
<TextInput
style={styles.input}
placeholder="Name"
value={participant.name}
onChangeText={(text) => {
const updatedParticipants = [...participants];
updatedParticipants[index].name = text;
setParticipants(updatedParticipants);
}}
/>
<TextInput
style={styles.input}
placeholder="Amount"
value={participant.amount}
onChangeText={(text) => {
const updatedParticipants = [...participants];
updatedParticipants[index].amount = text;
setParticipants(updatedParticipants);
}}
keyboardType="numeric"
/>
<TouchableOpacity
style={styles.removeButton}
onPress={() => removeParticipant(index)}
>
<Text style={styles.removeButtonText}>Remove</Text>
</TouchableOpacity>
</View>
))}
</ScrollView>
<TouchableOpacity style={styles.addButton} onPress={addParticipant}>
<Text style={styles.addButtonText}>Add Participant</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.calculateButton}
onPress={calculateSplit}>
<Text style={styles.calculateButtonText}>Calculate</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.resetButton} onPress={resetApp}>
<Text style={styles.resetButtonText}>Reset</Text>
</TouchableOpacity>
{/* Settled Transactions Box */}
<View style={styles.resultBox}>
<Text style={styles.resultsTitle}>Settle Transactions</Text>
<ScrollView style={styles.resultsList}>
{settleTransactions.map((transaction, index) => (
<Text key={index} style={styles.resultItem}>
{transaction.payer}
should pay
{transaction.payee} ${transaction.amount}
</Text>
))}
</ScrollView>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: 'white',
},
title: {
fontSize: 24,
textAlign: 'center',
marginVertical: 20,
},
participantList: {
marginBottom: 20,
},
participantItem: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 10,
},
input: {
flex: 1,
height: 40,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 5,
paddingHorizontal: 10,
},
addButton: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 5,
alignItems: 'center',
marginBottom: 10,
},
addButtonText: {
color: 'white',
fontSize: 16,
},
calculateButton: {
backgroundColor: '#34C759',
padding: 15,
borderRadius: 5,
alignItems: 'center',
},
calculateButtonText: {
color: 'white',
fontSize: 16,
},
resultsTitle: {
fontSize: 20,
marginVertical: 10,
},
resultsList: {
marginBottom: 20,
},
resultItem: {
fontSize: 16,
},
resetButton: {
backgroundColor: '#FF3B30',
padding: 15,
borderRadius: 5,
alignItems: 'center',
marginTop: 10,
},
resetButtonText: {
color: 'white',
fontSize: 16,
},
removeButton: {
backgroundColor: '#FF3B30',
padding: 10,
borderRadius: 100,
alignItems: 'center',
marginTop: 5,
marginLeft: 5,
},
removeButtonText: {
color: 'white',
fontSize: 12,
},
resultBox: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 5,
marginTop: 20,
padding: 5,
backgroundColor: '#CBF6B6',
elevation: 5,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 3,
},
});
export default BillSplitter;