The most effective way to learn how to code is by building real-life applications and putting yourself through actual project work. You’ll understand the syntax better, learn to research more effectively, become a better problem-solver, hone your UI/UX design skills, and understand the nuances that merely watching a tutorial won’t provide you.
Keeping this in mind, let’s build a resume builder app using React Native. In this tutorial, you’ll learn some important practical skills and techniques for mobile development.
Jump ahead:
A resume, or CV, is a document used by a person to present their skills, work experience, and accomplishments to a prospective employer. Resume builder apps make it easier to do so by prompting the user to fill in various fields with the appropriate information, then generating a clean, styled resume with that information.
In this project, we will create a resume builder app in React Native. The app’s user interface will include two screens.
The first screen will contain various input fields containing prompts for the user to provide information relevant to their resume, including their name, contact details, and past work experience:
Depending on the size of the user’s device, the number of fields shown in the viewport at any given time may vary. Once the user scrolls to the end of the form, they should see a button to submit their information:
After the user submits the form, we’ll collect all that information and display the resume on a second screen, as shown in the image below:
See the full source code for this project on Expo Snack.
At this point, you should have your Expo Snack project ready to edit. If so, create a new folder named screen
in the root folder of your project. Next, create two files in the screen
 folder —  ResumeForm.js
and ShowCV.js
.
Inside ResumeForm.js
, start by importing React, the useState()
Hook, and the various components for building out the UI, then define a barebone ResumeForm
component function as follows:
import * as React from 'react'; import { Text, View, StyleSheet, TextInput, Button, TouchableOpacity } from 'react-native'; import { useState } from 'react' export default function ResumeForm({ navigation }) { return ( // JSX goes here ) }
Before we start specifying the elements to render in return, let’s define the component state with the useState()
Hook.
Add the following code just before the return
statement:
const [userDetails, setUserDetails] = useState({ fullName: '', avatarUrl: '', profTitle: '', phoneNo: '', email: '', website: '', company: '', jobTitle: '', jobStartDate: '', jobEndDate: '', experience: '', profSummary: '', certificate: '', collegeName: '', colStartDate: '', colEndDate: '', skill: '', hobby: '' });
This object contains the information the user is required to provide via the form inputs. At the moment, it’s all empty. But we’ll use the setter method — setUserDetails
— to populate each state branch as the user types into their corresponding form inputs.
Next, in the return
statement, create the container <View>
element and a title text inside of it:
<View style={styles.container}> <View style={styles.header}> <Text style={styles.headerText}>Resume Builder</Text> </View> // Input groups will go here </View>
Now we need to start creating the different input groups.
The first input group is for collecting the user’s personal information — name, avatar URL, and job title.
We are collecting the data using React Native’s TextInput
element. Here’s the code to achieve this, which you should add inside the container View
:
<View style={styles.details}> <Text style={styles.titleText}>Personal Details</Text> <TextInput style={styles.textinput} placeholder="Enter your full name" value={userDetails.fullName} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'fullName': e} })); }} /> <TextInput style={styles.textinput} placeholder="Enter your avatar URL" value={userDetails.avatarUrl} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'avatarUrl': e} })); }} /> <TextInput style={styles.textinput} placeholder="Enter your professional title" value={userDetails.profTitle} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'profTitle': e} })); }} /> </View>
Each TextInput
has an onChangeText
property, which updates the state in real-time as the user types into the form input. Each setUserDetails
call updates only the corresponding branch in the state.
Let’s look at the third form input group as another example. The third form group is for collecting the user’s work experience information — previous job, start and end date, and a description of that job experience:
<View style={styles.details}> <Text style={styles.titleText}>Previous Job</Text> <TextInput style={styles.textinput} placeholder="Enter company name" value={userDetails.company} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'company': e} })); }} /> <TextInput style={styles.textinput} placeholder="Enter job title" value={userDetails.jobTitle} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'jobTitle': e} })); }} /> <TextInput style={styles.textinput} placeholder="Enter start date (e.g. 11/11/2022)" value={userDetails.jobStartDate} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'jobStartDate': e} })); }} /> <TextInput style={styles.textinput} placeholder="Enter end date (e.g. 12/11/2022)" value={userDetails.jobEndDate} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'jobEndDate': e} })); }} /> <TextInput style={styles.textinput} placeholder="Describe your experience" value={userDetails.experience} onChangeText={(e) => { setUserDetails(userDetails => ({ ...userDetails, ...{'experience': e} })); }} /> </View>
To keep things simple, we used TextInput
for the dates. You can integrate a React Native date picker library like react-native-date-picker
to make the project more interesting.
The second and fourth form groups use the same format as the ones covered so far, so I’ve excluded them to keep things short. You can refer to the Expo Snack repo to see what else we included in this example resume builder app.
Below the form input groups, let’s create the button for submitting the form using React Native’s Button
component:
<Button title="Create Resume" style={styles.button} onPress={() => navigation.navigate('ShowCV', userDetails)} > </Button>
Here, we specified that when the user presses the button, we want to navigate them to the ShowCV
screen, passing along the user’s resume information as the parameter. We will render the resume details to the user on the ShowCV
screen.
We’ll create ShowCV.js
in the next section. But first, let’s add some styling to our React Native resume builder app.
Underneath the Resume
function, paste the following stylesheet to make the form look better:
const styles = StyleSheet.create({ cont: { flex: 1, backgroundColor: '#36485f', paddingLeft: 40, paddingRight: 40, paddingTop: 40 }, header: { marginBottom: 20, alignSelf: 'stretch' }, details: { marginBottom: 15 }, headerText: { fontSize: 24, color: '#fff', borderBottomColor: '#199187', paddingBottom: 10, borderBottomWidth: 1 }, titleText: { fontWeight: 'bold', color: 'yellow', fontSize: 15, marginBottom: 10 }, textinput: { alignSelf: 'stretch', height: 40, color: '#d3d3d3', marginBottom: 20, borderBottomColor: '#f8f8f8', borderBottomWidth: 1 }, button: { alignSelf: 'stretch', alignItems: 'center', padding: 10, backgroundColor: '#59cbbd', marginTop: 5, marginBottom: 20, } });
Your application should now look like this:
Next up, let’s create ShowCV.js
.
In this section, we’ll create the ShowCV
screen to show the user their full resume. Go into your screens/ShowCV.js
file and include the following code:
import * as React from 'react'; import { Text, View, StyleSheet, TextInput, Button, TouchableOpacity } from 'react-native'; import { useState } from 'react' export default function ShowCV({ route }) { let dataObj = route.params return ( <View style={styles.container}> <View style={styles.header}> <Text style={styles.headerText}>Your Resume</Text> </View> // Resume details go here </View> ) }
When navigating from one screen to another, the destination screen has access to the root object. We’ll set up React Navigation in the next section.
Inside the ShowCV
function above, we assigned the route.params
object passed from the ResumeForm
screen to a new variable.
Next, render the details on the screen, starting with the user’s personal details  —  name, avatar image, and job title:
<View style={styles.details}> <Text style={styles.titleText}>Personal Details</Text> <Image source={{ uri: dataObj.avatarUrl }} style={{ width: 80, height: 80 }} /> <Text style={styles.text}> <Text style={styles.key}>Name: </Text> <Text>{dataObj.fullName}</Text> </Text> <Text style={styles.text}> <Text style={styles.key}>Professional Title: </Text> <Text>{dataObj.profTitle}</Text> </Text> </View>
We get the image URL from the avatarUrl
property, the name from the fullName
property, and the title from the profTitle
property.
The rest of the form groups are rendered in a similar way. We nest two Text
elements inside the main one. One contains the name of the property, such as Professional Title
. The other contains the actual value from dataObj
, such as Web
Developer
.
Once again, you can refer to the Expo Snack project to get the full source code.
When you’re done with the view, the next step is to make it look good. Paste the following stylesheet code underneath the ShowCV
function:
const styles = StyleSheet.create({ cont: { flex: 1, backgroundColor: '#36485f', paddingLeft: 40, paddingRight: 40, paddingTop: 40 }, header: { marginBottom: 20, alignSelf: 'stretch' }, details: { marginBottom: 15 }, headerText: { fontSize: 24, color: '#fff', borderBottomColor: '#199187', paddingBottom: 10, borderBottomWidth: 1 }, titleText: { fontWeight: 'bold', color: 'yellow', fontSize: 15, marginBottom: 10 }, key: { fontWeight: 'bold' }, text: { color: '#d3d3d3', } });
Both screens are now set. The next step is to create a screen navigator in App.js
to connect both screens together.
Inside App.js
, start by importing the following dependencies:
import * as React from 'react'; import ResumeForm from './screens/ResumeForm' import ShowCV from './screens/ShowCV' import { NavigationContainer } from "@react-navigation/native" import { createNativeStackNavigator } from "@react-navigation/native-stack"
On lines two and three, we imported the two screens we just created. Then, we imported NavigationContainer
from @react-navigation/native
and createNativeStackNavigator
from @react-navigation/native-stack
to help us connect the screens.
We need to install both of those libraries before we can use them.
If you’re following this tutorial on Expo Snack, you’ll get a message at the bottom of the screen prompting you to install both libraries. Accept all the prompts, including the prompts to install react-native-screens
and react-native-safearea
— both are needed for react-navigation
to work.
Next, call createNativeStackNavigator
to retrieve the Stack
:
const Stack = createNativeStackNavigator()
This Stack
allows you to “stack up” the screens you want to transition between in your app.
Create the App
component function and return both screens in the <Stack.Navigation>
as shown below. Make sure to wrap the Stack.Navigator
in the <NavigationProvider>
or it won’t work:
export default function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Resume" component = {ResumeForm} /> <Stack.Screen name="ShowCV" component = {ShowCV} /> </Stack.Navigator> </NavigationContainer> ); }
The ResumeForm
screen is placed on top of the stack, meaning the app will first render the ResumeForm
component when it finishes loading.
Now everything is set. You can test the app by filling out the form and clicking the Create Resume
button. You should see all the information in the ShowCV
screen as follows:
Now you know all it takes to build a resume builder app in React Native. We covered the technique for navigating between screens in React Native applications.
I recommend that you just don’t stop here — build on this React Native tutorial to customize and enhance this resume builder app. For example, you can validate the form inputs to make sure that they are filled before the form can be submitted.
Also, you can integrate a date picker library like react-native-date-picker
to enforce custom rules for the start and end dates in your form or ensure that the dates are valid. Both are great opportunities to learn new things.
Thanks for following and have a great week.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowReact Native’s New Architecture offers significant performance advantages. In this article, you’ll explore synchronous and asynchronous rendering in React Native through practical use cases.
Build scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.