How to Create a Basic Notes App using React Native?
In this article, we'll walk you through the process of building a basic notes app using React Native. The application enables users to effortlessly create, edit, and delete notes, providing an uncomplicated yet impactful introduction to React Native's mobile app development capabilities.

To give you a better idea of what we’re going to create, let’s watch a demo video.
Demo Video
Prerequisites:
- Introduction to React Native
- Introduction to React Native Components
- React Native State
- React Native Props
- Expo CLI
- Node.js and npm (Node Package Manager)
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
This code snippet in React Native allows you to build a simple notes app effortlessly. It effectively manages the state using useState, enabling you to handle note data, editing functionality, and modal visibility smoothly. The app's interface presents a scrollable list of notes, each featuring a title. By utilizing modals with title and content inputs, users can easily add, edit, and delete notes.
- Import libraries: Import required libraries at the top of the file.
// Import necessary hooks and components from React and React Native
import { useState } from "react";
import {
View, // Container component for layout
Text, // Component for displaying text
TextInput, // Component for user text input
Button, // Button component
ScrollView, // Scrollable container for lists
TouchableOpacity, // Pressable component for touch interactions
Modal, // Modal dialog component
StyleSheet, // Utility for creating styles
} from "react-native";
- StyleSheet: Create a StyleSheet to style components like container, title, noteList, etc.
// Styles for the components
const styles = StyleSheet.create({
container: {
flex: 1, // Fill the screen
padding: 40, // Padding around content
backgroundColor: "#e6e6e6",// Light gray background
},
title: {
fontSize: 24, // Large font size
fontWeight: "bold", // Bold text
marginBottom: 10, // Space below title
color: "#333", // Dark text color
},
noteList: {
flex: 1, // Take up remaining space
},
noteTitle: {
fontSize: 15, // Medium font size
marginBottom: 10, // Space below each note
fontWeight: "bold", // Bold text
color: "black", // Black text
backgroundColor: "white", // White background
height: 40, // Fixed height
width: "100%", // Full width
padding: 10, // Padding inside note
borderRadius: 8, // Rounded corners
},
addButton: {
alignItems: "center", // Center text horizontally
justifyContent: "center", // Center text vertically
backgroundColor: "#007BFF",// Blue background
paddingVertical: 12, // Vertical padding
borderRadius: 5, // Rounded corners
marginTop: 10, // Space above button
},
addButtonText: {
color: "white", // White text
fontSize: 16, // Medium font size
fontWeight: "bold", // Bold text
},
modalContainer: {
flex: 1, // Fill the modal
padding: 50, // Padding inside modal
backgroundColor: "white", // White background
},
input: {
borderWidth: 1, // Border width
borderColor: "#E0E0E0", // Light gray border
padding: 10, // Padding inside input
marginBottom: 10, // Space below input
borderRadius: 5, // Rounded corners
},
contentInput: {
borderWidth: 1, // Border width
borderColor: "#E0E0E0", // Light gray border
padding: 10, // Padding inside input
marginBottom: 20, // Space below input
borderRadius: 5, // Rounded corners
height: 150, // Height for multiline input
textAlignVertical: "top", // Start text at the top
},
buttonContainer: {
flexDirection: "row", // Arrange buttons in a row
justifyContent: "space-between", // Space buttons evenly
},
});
- Add Note Button: By putting the Text component ("Add Note") inside a TouchableOpacity component, we can make the text act like a button. When the user taps on it, it clears the text and content, then opens a dialog box to ask for input from the user.
{/* Button to add a new note */}
<TouchableOpacity
style={styles.addButton}
onPress={() => {
setTitle(""); // Clear title input
setContent(""); // Clear content input
setModalVisible(true); // Open modal dialog
}}
>
<Text style={styles.addButtonText}>
Add Note {/* Button label */}
</Text>
</TouchableOpacity>
- Modal dialog: When user taps on "Add Note" button, it is executing below statement in onPress.
setModalVisible(true); // Open modal dialog
It will change the value of modalVisible to True using useState, and if the Modal component prop "visible" becomes true, then it will display whatever code it contains on screen.
It contains:
UI Element | Description |
---|---|
Title TextInput | It is used to take the "Title" of the Note from the user. |
Content TextInput | It is used to take the "Content" of the Note from the user. |
Save Button | It is used to save the title and content in the notes array using the handleSaveNote function. |
Cancel Button | It is used to reset or hide the Modal dialog by calling setModalVisible with false as a parameter. |
Delete Button | This button will only display when you are updating and it will delete the parameter note, when user taps on it by calling handleDeleteNote function. |
Code:
// State variable: Controls visibility of the modal dialog
const [modalVisible, setModalVisible] = useState(false);
{/* Modal dialog for creating or editing notes */}
<Modal
visible={modalVisible} // Show/hide modal
animationType="slide" // Slide animation
transparent={false} // Modal is not transparent
>
<View style={styles.modalContainer}>
{/* Input for note title */}
<TextInput
style={styles.input}
placeholder="Enter note title" // Placeholder text
value={title} // Controlled value
onChangeText={setTitle} // Update title state on change
/>
{/* Input for note content (multiline) */}
<TextInput
style={styles.contentInput}
multiline // Allow multiple lines
placeholder="Enter note content" // Placeholder text
value={content} // Controlled value
onChangeText={setContent} // Update content state on change
/>
{/* Container for action buttons */}
<View style={styles.buttonContainer}>
{/* Save button */}
<Button
title="Save"
onPress={handleSaveNote} // Save note on press
color="#007BFF"
/>
{/* Cancel button */}
<Button
title="Cancel"
onPress={() =>
setModalVisible(false) // Close modal on press
}
color="#FF3B30"
/>
{/* Delete button (only shown when editing an existing note) */}
{selectedNote && (
<Button
title="Delete"
onPress={() =>
handleDeleteNote(
selectedNote // Delete selected note on press
)
}
color="#FF9500"
/>
)}
</View>
</View>
</Modal>
- handleSaveNote function: This function will update the particular note when user selects an existed note or create a new note with id, title and content by calling the useState of SetNotes, after creating or updating it will clear the title, content TextInputs and hides Model dialog by calling modalVisible useState.
// State variable: Array to store all notes
const [notes, setNotes] = useState([]);
// State variable: Controls visibility of the modal dialog
const [modalVisible, setModalVisible] = useState(false);
// Function to handle saving a note (either add new or update existing)
const handleSaveNote = () => {
if (selectedNote) {
// If editing an existing note, update it in the notes array
const updatedNotes = notes.map((note) =>
note.id === selectedNote.id
? { ...note, title, content } // Update title and content
: note // Leave other notes unchanged
);
setNotes(updatedNotes); // Update notes state
setSelectedNote(null); // Clear selected note
} else {
// If adding a new note, create a new note object
const newNote = {
id: Date.now(), // Unique ID based on timestamp
title, // Note title
content, // Note content
};
setNotes([...notes, newNote]); // Add new note to notes array
}
setTitle(""); // Clear title input
setContent(""); // Clear content input
setModalVisible(false); // Close modal dialog
};
- handleDeleteNode function: It will delete the particular note from notes array and updating the notes by calling SetNotes useState, passing null to setSelectedNote useState to clear the selected note and call setModalVisible with false as value to hide the Model dialog.
// State variable: Array to store all notes
const [notes, setNotes] = useState([]);
// State variable: Currently selected note for editing
const [selectedNote, setSelectedNote] = useState(null);
// State variable: Controls visibility of the modal dialog
const [modalVisible, setModalVisible] = useState(false);
// Function to handle deleting a note
const handleDeleteNote = (note) => {
// Remove the selected note from the notes array
const updatedNotes = notes.filter(
(item) => item.id !== note.id // Keep notes that don't match the deleted note's id
);
setNotes(updatedNotes); // Update notes state
setSelectedNote(null); // Clear selected note
setModalVisible(false); // Close modal dialog
};
- Display Notes: We can show a list of notes using the code below. By going through the notes array using map, we can easily get the ID, title, and content of each note. We use the Text component to display the title. When a user taps on a note in the list, we call the handleEditNote function using the TouchableOpacity component. We also make all the notes in the list scrollable by using the ScrollView component.
{/* Scrollable list of notes */}
<ScrollView style={styles.noteList}>
{notes.map((note) => (
// Each note is a touchable item that opens the edit modal
<TouchableOpacity
key={note.id} // Unique key for each note
onPress={() => handleEditNote(note)} // Edit note on press
>
<Text style={styles.noteTitle}>
{note.title} {/* Display note title */}
</Text>
</TouchableOpacity>
))}
</ScrollView>
- handleEditNote function: This function will open a modal dialog with the chosen note's information. It will use setSelectedNote to set the selected note. Then, it will use setTitle and setContent to set the title and content of the note. After that, it will close the modal dialog by calling setModalVisible.
// State variable: Currently selected note for editing
const [selectedNote, setSelectedNote] = useState(null);
// State variable: Title of the note being created/edited
const [title, setTitle] = useState("");
// State variable: Content of the note being created/edited
const [content, setContent] = useState("");
// State variable: Controls visibility of the modal dialog
const [modalVisible, setModalVisible] = useState(false);
// Function to handle editing a note (opens modal with note data)
const handleEditNote = (note) => {
setSelectedNote(note); // Set the note to be edited
setTitle(note.title); // Set title input to note's title
setContent(note.content); // Set content input to note's content
setModalVisible(true); // Open modal dialog
};
Now, wrap the Add Note Button, Modal, and list of notes with a View component and return from the App component. Also, ensure to export the App.
Complete Source Code
App.js:
// Import necessary hooks and components from React and React Native
import { useState } from "react";
import {
View, // Container component for layout
Text, // Component for displaying text
TextInput, // Component for user text input
Button, // Button component
ScrollView, // Scrollable container for lists
TouchableOpacity, // Pressable component for touch interactions
Modal, // Modal dialog component
StyleSheet, // Utility for creating styles
} from "react-native";
// Main App component
const App = () => {
// State variable: Array to store all notes
const [notes, setNotes] = useState([]);
// State variable: Currently selected note for editing
const [selectedNote, setSelectedNote] = useState(null);
// State variable: Title of the note being created/edited
const [title, setTitle] = useState("");
// State variable: Content of the note being created/edited
const [content, setContent] = useState("");
// State variable: Controls visibility of the modal dialog
const [modalVisible, setModalVisible] = useState(false);
// Function to handle saving a note (either add new or update existing)
const handleSaveNote = () => {
if (selectedNote) {
// If editing an existing note, update it in the notes array
const updatedNotes = notes.map((note) =>
note.id === selectedNote.id
? { ...note, title, content } // Update title and content
: note // Leave other notes unchanged
);
setNotes(updatedNotes); // Update notes state
setSelectedNote(null); // Clear selected note
} else {
// If adding a new note, create a new note object
const newNote = {
id: Date.now(), // Unique ID based on timestamp
title, // Note title
content, // Note content
};
setNotes([...notes, newNote]); // Add new note to notes array
}
setTitle(""); // Clear title input
setContent(""); // Clear content input
setModalVisible(false); // Close modal dialog
};
// Function to handle editing a note (opens modal with note data)
const handleEditNote = (note) => {
setSelectedNote(note); // Set the note to be edited
setTitle(note.title); // Set title input to note's title
setContent(note.content); // Set content input to note's content
setModalVisible(true); // Open modal dialog
};
// Function to handle deleting a note
const handleDeleteNote = (note) => {
// Remove the selected note from the notes array
const updatedNotes = notes.filter(
(item) => item.id !== note.id // Keep notes that don't match the deleted note's id
);
setNotes(updatedNotes); // Update notes state
setSelectedNote(null); // Clear selected note
setModalVisible(false); // Close modal dialog
};
// Render the UI
return (
<View style={styles.container}>
{/* App title */}
<Text style={styles.title}>My Notes</Text>
{/* Scrollable list of notes */}
<ScrollView style={styles.noteList}>
{notes.map((note) => (
// Each note is a touchable item that opens the edit modal
<TouchableOpacity
key={note.id} // Unique key for each note
onPress={() => handleEditNote(note)} // Edit note on press
>
<Text style={styles.noteTitle}>
{note.title} {/* Display note title */}
</Text>
</TouchableOpacity>
))}
</ScrollView>
{/* Button to add a new note */}
<TouchableOpacity
style={styles.addButton}
onPress={() => {
setTitle(""); // Clear title input
setContent(""); // Clear content input
setModalVisible(true); // Open modal dialog
}}
>
<Text style={styles.addButtonText}>
Add Note {/* Button label */}
</Text>
</TouchableOpacity>
{/* Modal dialog for creating or editing notes */}
<Modal
visible={modalVisible} // Show/hide modal
animationType="slide" // Slide animation
transparent={false} // Modal is not transparent
>
<View style={styles.modalContainer}>
{/* Input for note title */}
<TextInput
style={styles.input}
placeholder="Enter note title" // Placeholder text
value={title} // Controlled value
onChangeText={setTitle} // Update title state on change
/>
{/* Input for note content (multiline) */}
<TextInput
style={styles.contentInput}
multiline // Allow multiple lines
placeholder="Enter note content" // Placeholder text
value={content} // Controlled value
onChangeText={setContent} // Update content state on change
/>
{/* Container for action buttons */}
<View style={styles.buttonContainer}>
{/* Save button */}
<Button
title="Save"
onPress={handleSaveNote} // Save note on press
color="#007BFF"
/>
{/* Cancel button */}
<Button
title="Cancel"
onPress={() =>
setModalVisible(false) // Close modal on press
}
color="#FF3B30"
/>
{/* Delete button (only shown when editing an existing note) */}
{selectedNote && (
<Button
title="Delete"
onPress={() =>
handleDeleteNote(
selectedNote // Delete selected note on press
)
}
color="#FF9500"
/>
)}
</View>
</View>
</Modal>
</View>
);
};
// Styles for the components
const styles = StyleSheet.create({
container: {
flex: 1, // Fill the screen
padding: 40, // Padding around content
backgroundColor: "#e6e6e6",// Light gray background
},
title: {
fontSize: 24, // Large font size
fontWeight: "bold", // Bold text
marginBottom: 10, // Space below title
color: "#333", // Dark text color
},
noteList: {
flex: 1, // Take up remaining space
},
noteTitle: {
fontSize: 15, // Medium font size
marginBottom: 10, // Space below each note
fontWeight: "bold", // Bold text
color: "black", // Black text
backgroundColor: "white", // White background
height: 40, // Fixed height
width: "100%", // Full width
padding: 10, // Padding inside note
borderRadius: 8, // Rounded corners
},
addButton: {
alignItems: "center", // Center text horizontally
justifyContent: "center", // Center text vertically
backgroundColor: "#007BFF",// Blue background
paddingVertical: 12, // Vertical padding
borderRadius: 5, // Rounded corners
marginTop: 10, // Space above button
},
addButtonText: {
color: "white", // White text
fontSize: 16, // Medium font size
fontWeight: "bold", // Bold text
},
modalContainer: {
flex: 1, // Fill the modal
padding: 50, // Padding inside modal
backgroundColor: "white", // White background
},
input: {
borderWidth: 1, // Border width
borderColor: "#E0E0E0", // Light gray border
padding: 10, // Padding inside input
marginBottom: 10, // Space below input
borderRadius: 5, // Rounded corners
},
contentInput: {
borderWidth: 1, // Border width
borderColor: "#E0E0E0", // Light gray border
padding: 10, // Padding inside input
marginBottom: 20, // Space below input
borderRadius: 5, // Rounded corners
height: 150, // Height for multiline input
textAlignVertical: "top", // Start text at the top
},
buttonContainer: {
flexDirection: "row", // Arrange buttons in a row
justifyContent: "space-between", // Space buttons evenly
},
});
// Export the App component as default
export default App;