Build a Calculator using React Native
Building a simple calculator app in React Native is an exciting project. You'll create an interface with buttons for numbers (0-9) and operations (+, -, ×, ÷), along with a display area for showing input and results. Using React Native, you'll write functions that handle button presses and perform calculations. This project combines UI design with JavaScript logic, making it a great way to learn.

To give you a better idea of what we’re going to create, let’s watch a demo video.
Demo Video
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-name
Project Structure:

Step 2: Run Application
Start the server by using the following command.
npx expo start
Then, 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
- Import libraries: Import required libraries at the top of the file.
import {
useState, // Hook for managing component state
useEffect // Hook for performing side effects in function components
} from 'react'; // Import React hooks for state and side effects
import {
SafeAreaView, // A container that ensures content is rendered within the safe area boundaries of a device
Text, // Component for displaying text
View, // A container for grouping other components
TouchableOpacity, // A button-like component that responds to touch events
StyleSheet, // Utility for creating styles for components
} from 'react-native'; // Import React Native components for UI
- StyleSheet: Create a StyleSheet to style components like container, resultContainer, inputText, resultText, buttonsContainer, row, button, equalsButton, and buttonText.
// Define styles for the app
const styles = StyleSheet.create({
container: {
flex: 1, // Take up the full screen
backgroundColor: '#000', // Black background
justifyContent: 'space-between', // Space out elements vertically
},
resultContainer: {
padding: 50, // Add padding around the result area
alignItems: 'flex-end', // Align text to the right
},
inputText: {
fontSize: 36, // Large font for input
color: '#AFAFAF', // Light gray color
},
resultText: {
fontSize: 40, // Larger font for result
color: '#fff', // White color
marginTop: 10, // Add spacing above the result
},
buttonsContainer: {
padding: 10, // Add padding around the buttons
marginBottom: 10, // Add margin at the bottom
},
row: {
flexDirection: 'row', // Arrange buttons in a row
justifyContent: 'space-between', // Space out buttons evenly
marginVertical: 6, // Add vertical spacing between rows
},
button: {
backgroundColor: '#1c1c1c', // Dark gray background for buttons
flex: 1, // Buttons take equal space
alignItems: 'center', // Center button text horizontally
justifyContent: 'center', // Center button text vertically
margin: 5, // Add spacing between buttons
height: 70, // Set button height
borderRadius: 35, // Make buttons circular
},
equalsButton: {
backgroundColor: '#1FD660', // Green background for '=' button
flex: 4, // Make '=' button wider
},
buttonText: {
fontSize: 24, // Default font size for button text
color: '#fff', // White text color
},
});
- buttons: Define a list of buttons for the calculator.
// Define the layout of calculator buttons
const buttons = [
['C', '(', ')', '%'], // First row of buttons
['7', '8', '9', '/'], // Second row of buttons
['4', '5', '6', '*'], // Third row of buttons
['1', '2', '3', '-'], // Fourth row of buttons
['+/-', '0', '.', '+'], // Fifth row of buttons
['='], // Sixth row with only the equals button
];
- buttons UI: Use the code below to show a list of buttons. Organize the buttons with a map function and display the text for each button using a Text component. Make the buttons interactive by wrapping the Text inside a TouchableOpacity. This way, when the user taps on any button, it will call the handlePress function.
{/* Render the calculator buttons */}
<View style={styles.buttonsContainer}>
{buttons.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{row.map((btn, colIndex) => (
<TouchableOpacity
key={colIndex}
style={[
styles.button,
btn === '=' ? styles.equalsButton : null, // Apply special style for '=' button
]}
onPress={() => handlePress(btn)} // Handle button press
>
<Text style={[styles.buttonText, btn === '=' && { fontSize: 28 }]}>
{btn} {/* Display the button label */}
</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
- Input Text & Result Text: Display Input Text (Text user typing) and Result Text ( Answer to user input) using Text component wrapped with View component.
{/* Display the input and result */}
<View style={styles.resultContainer}>
<Text style={styles.inputText}>{input + " "}</Text> {/* Show the current input */}
<Text style={styles.resultText}>{result + " "}</Text> {/* Show the calculated result */}
</View>
- handlePress: Function to make every button functional.
const handlePress = (btn) => {
if (btn === 'C') {
// Clear input and result when 'C' is pressed
setInput('');
setResult('');
} else if (btn === '=') {
// Do nothing since the result is calculated automatically
} else if (btn === '+/-') {
// Toggle the sign of the input
if (input.startsWith('-')) setInput(input.substring(1));
else setInput('-' + input);
} else {
// Append the button value to the input
setInput((prev) => prev + btn);
}
};
- useState: Used to manage the state of input and result.
// State to store the current input
const [input, setInput] = useState('');
// State to store the calculated result
const [result, setResult] = useState('');
- useEffect: Used to calculate the result whenever the input changes.
// Effect to calculate the result whenever the input changes
useEffect(() => {
try {
if (input) {
// Replace custom operators with JavaScript-compatible ones
let finalInput = input.replace(/×/g, '*').replace(/÷/g, '/');
// Evaluate the expression and update the result
const evalResult = eval(finalInput);
setResult(evalResult.toString());
} else {
// Clear the result if input is empty
setResult('');
}
} catch (e) {
// Handle invalid expressions gracefully
setResult('');
}
}, [input]); // Dependency array ensures this runs when `input` changes
Now, wrap the buttons UI, input Text & result Text components with a SafeAreaView component and return from the App component. Also, ensure to export the App.
Complete Source Code
App.js:
import {
useState, // Hook for managing component state
useEffect // Hook for performing side effects in function components
} from 'react'; // Import React hooks for state and side effects
import {
SafeAreaView, // A container that ensures content is rendered within the safe area boundaries of a device
Text, // Component for displaying text
View, // A container for grouping other components
TouchableOpacity, // A button-like component that responds to touch events
StyleSheet, // Utility for creating styles for components
} from 'react-native'; // Import React Native components for UI
// Define the layout of calculator buttons
const buttons = [
['C', '(', ')', '%'], // First row of buttons
['7', '8', '9', '/'], // Second row of buttons
['4', '5', '6', '*'], // Third row of buttons
['1', '2', '3', '-'], // Fourth row of buttons
['+/-', '0', '.', '+'], // Fifth row of buttons
['='], // Sixth row with only the equals button
];
const App = () => {
// State to store the current input
const [input, setInput] = useState('');
// State to store the calculated result
const [result, setResult] = useState('');
// Effect to calculate the result whenever the input changes
useEffect(() => {
try {
if (input) {
// Replace custom operators with JavaScript-compatible ones
let finalInput = input.replace(/×/g, '*').replace(/÷/g, '/');
// Evaluate the expression and update the result
const evalResult = eval(finalInput);
setResult(evalResult.toString());
} else {
// Clear the result if input is empty
setResult('');
}
} catch (e) {
// Handle invalid expressions gracefully
setResult('');
}
}, [input]); // Dependency array ensures this runs when `input` changes
// Function to handle button presses
const handlePress = (btn) => {
if (btn === 'C') {
// Clear input and result when 'C' is pressed
setInput('');
setResult('');
} else if (btn === '=') {
// Do nothing since the result is calculated automatically
} else if (btn === '+/-') {
// Toggle the sign of the input
if (input.startsWith('-')) setInput(input.substring(1));
else setInput('-' + input);
} else {
// Append the button value to the input
setInput((prev) => prev + btn);
}
};
return (
<SafeAreaView style={styles.container}>
{/* Display the input and result */}
<View style={styles.resultContainer}>
<Text style={styles.inputText}>{input + " "}</Text> {/* Show the current input */}
<Text style={styles.resultText}>{result + " "}</Text> {/* Show the calculated result */}
</View>
{/* Render the calculator buttons */}
<View style={styles.buttonsContainer}>
{buttons.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{row.map((btn, colIndex) => (
<TouchableOpacity
key={colIndex}
style={[
styles.button,
btn === '=' ? styles.equalsButton : null, // Apply special style for '=' button
]}
onPress={() => handlePress(btn)} // Handle button press
>
<Text style={[styles.buttonText, btn === '=' && { fontSize: 28 }]}>
{btn} {/* Display the button label */}
</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
</SafeAreaView>
);
};
// Define styles for the app
const styles = StyleSheet.create({
container: {
flex: 1, // Take up the full screen
backgroundColor: '#000', // Black background
justifyContent: 'space-between', // Space out elements vertically
},
resultContainer: {
padding: 50, // Add padding around the result area
alignItems: 'flex-end', // Align text to the right
},
inputText: {
fontSize: 36, // Large font for input
color: '#AFAFAF', // Light gray color
},
resultText: {
fontSize: 40, // Larger font for result
color: '#fff', // White color
marginTop: 10, // Add spacing above the result
},
buttonsContainer: {
padding: 10, // Add padding around the buttons
marginBottom: 10, // Add margin at the bottom
},
row: {
flexDirection: 'row', // Arrange buttons in a row
justifyContent: 'space-between', // Space out buttons evenly
marginVertical: 6, // Add vertical spacing between rows
},
button: {
backgroundColor: '#1c1c1c', // Dark gray background for buttons
flex: 1, // Buttons take equal space
alignItems: 'center', // Center button text horizontally
justifyContent: 'center', // Center button text vertically
margin: 5, // Add spacing between buttons
height: 70, // Set button height
borderRadius: 35, // Make buttons circular
},
equalsButton: {
backgroundColor: '#1FD660', // Green background for '=' button
flex: 4, // Make '=' button wider
},
buttonText: {
fontSize: 24, // Default font size for button text
color: '#fff', // White text color
},
});
export default App; // Export the App component as the default export