Progressive React Applications respond very fast to user actions. They load fast and are engaging just like a mobile app. They can access Mobile device features, leverage the Operating System, and have a very high reach. It enables Installability, Background Syncing, Caching and Offline Support, and other features like Push Notifications. With React, we can very easily enhance web apps progressively to look and feel like native mobile applications.
Prerequisites:
Now let’s see step-by-step implementation on how to develop a Progressive Web Application using React.
Steps to develop a Progressive Web App using ReactJS
Step 1: Initialize React Project with pwa
With ReactJS, it is even easier to create a Progressive Web App or even convert an existing React project into one. In the terminal of your text editor, enter the following command. CRA creates a boilerplate for Progressive Web App that you can easily modify according to your needs.
npx create-react-app react-pwa --template cra-template-pwa
cd react-pwa
This command creates a new React Application named react-pwa and navigates to the directory of your app. You can further modify your manifest.json file and other files like the logo to customize the app and make it your own.
Step 2: Install Required Modules
Let’s implement the functionalities of a PWA and add more features to our App. In the terminal of your text editor enter the following command to install some third-party and npm packages.
npm i --save web-push react-router-dom bootstrap react-bootstrap
Add worker.js and feed.js in your public folder and a components folder inside your src folder,
Project Structure:

Project Structure
The updated dependencies list in package.json file.
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.2",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"react-scripts": "5.0.1",
"web-push": "^3.6.6",
"web-vitals": "^2.1.4",
"workbox-background-sync": "^6.6.0",
"workbox-broadcast-update": "^6.6.0",
"workbox-cacheable-response": "^6.6.0",
"workbox-core": "^6.6.0",
"workbox-expiration": "^6.6.0",
"workbox-google-analytics": "^6.6.0",
"workbox-navigation-preload": "^6.6.0",
"workbox-precaching": "^6.6.0",
"workbox-range-requests": "^6.6.0",
"workbox-routing": "^6.6.0",
"workbox-strategies": "^6.6.0",
"workbox-streams": "^6.6.0"
},
Step 3: Register a Service Worker
A Service Worker is a special kind of script file that works between the browser and the network. It helps us to perform unique functionalities and registers itself whenever a page is loaded. To register a new service worker in your React App, in the worker.js file in your public folder (public/worker.js), add the following code.
Javascript
let STATIC_CACHE_NAME = "gfg-pwa" ;
let DYNAMIC_CACHE_NAME = "dynamic-gfg-pwa" ;
let urlsToCache = [ "/" , "/search" , "/aboutus" , "/profile" ];
self.addEventListener( "install" , (event) => {
event.waitUntil(
caches
.open(STATIC_CACHE_NAME)
.then( function (cache) {
console.log( "Opened cache" );
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener( "fetch" , (event) => {
event.respondWith(
caches.match(event.request).then((cacheRes) => {
return (
cacheRes ||
fetch(event.request).then((fetchRes) => {
return caches
.open(DYNAMIC_CACHE_NAME)
.then((cache) => {
cache.put(
event.request.url,
fetchRes.clone()
);
return fetchRes;
});
})
);
})
);
});
self.addEventListener( "activate" , (event) => {
let cacheWhitelist = [ "gfg-pwa" ];
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (
cacheWhitelist.indexOf(
cacheName
) === -1
) {
return caches. delete (cacheName);
}
})
);
})
);
});
|
Step 4: Checking Service Worker support for browser
Some old browsers may not support service workers. However, most modern browsers like Google Chrome have in-built support for service workers. In case of the absence of support, the app will run like a normal web application. To make sure that we don’t run into an error or the app doesn’t crash, we need to check whether the support status of service workers in the browser of the client. To do so, update your index.html file in the public folder (public/index.html) with the following code.
HTML
< script >
if ("serviceWorker" in navigator) {
window.addEventListener("load", function () {
navigator.serviceWorker
.register("/worker.js")
.then(
function (registration) {
console.log(
"Worker registration successful",
registration.scope);
},
function (err) {
console.log("Worker registration failed", err);
}
)
.catch(function (err) {
console.log(err);
});
});
} else {
console.log("Service Worker is not"
+ " supported by browser.");
}
</ script >
|
Step 5: Add Step to Register theService Worker
Now, that we have the code for the basic functionalities of a service worker. We need to register it. To do so, change one line in index.js in the src folder (src/index.js) from
service-worker.unregister()
to
serviceWorker.register()
Our service worker i.e. worker.js will now successfully register itself.
Step to run the application: Now, enter the following command in the terminal of your text editor.
npm start
Output: This will open your React App in the localhost://3000 in the browser. And, in ṯhe Dev Tools, under Application Tab, you can see that your service worker is registered with a “Worker registration successful” message in your console.

Service Worker Registered
Explanation: We now have the basic service worker functioning just the way we want it to. To implement other native device-like features, let us implement to send a notification in case the user goes offline while using the app. Also, to see your new features, there is no need to run the app again, just clicking on reload button will do the trick.
Step 6: Sending a Push Notification when Offline
Push Notifications are a native mobile feature. And the browser will automatically ask for user permission in default settings. Web-push is a third-party package that will aid us with VAPID keys to push a notification. Now, we need to have a VAPID API Key to start implementing Push notifications in our App. Note that every VAPID API KEY is unique for every service worker.
To generate the API Keys, type the following in the terminal:
./node_modules/.bin/web-push generate-vapid-keys
Now, in the terminal of your text editor, web-push provides two of your own vapid keys. We are going to use the public vapid key to generate push notifications.
Modify the script in index.html. This will encode your base64 string VAPID API KEY and connect it with the service worker so that it is able to send notifications.
HTML
< script >
if ("serviceWorker" in navigator) {
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 -
(base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length ; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function determineAppServerKey() {
var vapidPublicKey =
"YOUR_PUBLIC_KEY" ;
return urlBase64ToUint8Array(vapidPublicKey);
}
window.addEventListener("load", function () {
navigator.serviceWorker
.register("/worker.js")
.then(
function (registration) {
console.log(
"Worker registration successful",
registration.scope
);
return registration.pushManager
.getSubscription()
.then(function (subscription) {
registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: determineAppServerKey(),
});
});
},
function (err) {
console.log("Worker registration failed", err);
}
)
.catch(function (err) {
console.log(err);
});
});
} else {
console.log("Service Worker is not supported by browser.");
}
</script>
|
Step 7: Implement Push Notification Functionality
Let’s use this new functionality to send push notifications whenever we go offline. In worker.js modify the fetch event and add the following code. Inside the show notification function, you can add more properties and modify them according to your wishes.
Javascript
self.addEventListener( "fetch" , (event) => {
event.respondWith(
caches.match(event.request).then((cacheRes) => {
return (
cacheRes ||
fetch(event.request).then((fetchRes) => {
return caches
.open(DYNAMIC_CACHE_NAME)
.then((cache) => {
cache.put(
event.request.url,
fetchRes.clone()
);
return fetchRes;
});
})
);
})
);
if (!navigator.onLine) {
if (
event.request.url ===
) {
event.waitUntil(
self.registration.showNotification(
"Internet" ,
{
body: "internet not working" ,
icon: "logo.png" ,
}
)
);
}
}
});
|
The self.registration.showNotification function shows the desired notification and even asks for permission before showing one.
Step 8: To check that Syncing and Caching work when offline, you can change the status above your Service Worker in Dev Tools to ‘offline’ or do the same above the app. Now, whenever you go offline, you will see a push notification indicating that you went offline.

Push Notification: Internet Not Working
Note that you are still able to see the pages though some functionalities might be lost. This is because these default pages and URLs once visited get stored in the cache. So, make sure to unregister and register it again under the Application Tab every time you make changes in your files during development.
Step 9: Adding Native Features like Camera and Geolocation – PWA enables using native features like accessing the webcam and figuring out location with the help of service workers. Let’s start with creating the UI for this first where we can use these functionalities, create a Profile.js file in ‘src/Profile.js’ which we can navigate to via /profile using React Routes.
Javascript
import React from "react" ;
import {
InputGroup,
Button,
Container,
} from "react-bootstrap" ;
const Profile = () => {
return (
<>
<Container className={style.styling}>
<br></br>
<InputGroup className= "mb-3" >
<InputGroup.Text>
Latitude
</InputGroup.Text>
<InputGroup.Text id= "latitude" >
00
</InputGroup.Text>
</InputGroup>
<br></br>
<InputGroup className= "mb-3" >
<InputGroup.Text>
Longitude
</InputGroup.Text>
<InputGroup.Text id= "longitude" >
00
</InputGroup.Text>
</InputGroup>
<br></br>
<InputGroup className= "mb-3" >
<InputGroup.Text>
Location
</InputGroup.Text>
</InputGroup>
<Button
variant= "outline-secondary"
id= "locationBtn"
>
Get Location
</Button>
<br></br>
<br></br>
<Button
variant= "outline-secondary"
id= "photoBtn"
>
Take a Picture Now!
</Button>
<video
id= "player"
autoPlay
width= "320px"
height= "240px"
></video>
<canvas
id= "canvas"
width= "320px"
height= "240px"
style={{ display: "none" }}
></canvas>
<Button
variant= "outline-secondary"
id= "capture"
>
Capture
</Button>
<br></br>
<div id= "pick-image" >
<h6>Pick an Image instead</h6>
<input
type= "file"
accept= "image/*"
id= "image-picker"
></input>
</div>
<br></br>
<br></br>
</Container>
</>
);
};
export default Profile;
|
Step 10: Now let’s add a feed.js file in public/feed.js to implement the functionality of location and camera.
Javascript
window.onload = function () {
let photo = document.getElementById( "photoBtn" );
let locationBtn =
document.getElementById( "locationBtn" );
locationBtn.addEventListener( "click" , handler);
let capture = document.getElementById( "capture" );
photo.addEventListener( "click" , initializeMedia);
capture.addEventListener( "click" , takepic);
};
function initializeLocation() {
if (!( "geolocation" in navigator)) {
locationBtn.style.display = "none" ;
}
}
function handler(event) {
if (!( "geolocation" in navigator)) {
return ;
}
navigator.geolocation.getCurrentPosition( function (
position
) {
console.log(position);
let lat = position.coords.latitude;
let lon = position.coords.longitude;
console.log(lat);
console.log(lon);
latitude.innerHTML = lat;
longitude.innerHTML = lon;
});
}
function initializeMedia() {
if (!( "mediaDevices" in navigator)) {
navigator.mediaDevices = {};
}
if (!( "getUserMedia" in navigator.mediaDevices)) {
navigator.mediaDevices.getUserMedia = function (
constraints
) {
let getUserMedia =
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(
new Error(
"getUserMedia is not implemented!"
)
);
}
return new Promise( function (resolve, reject) {
getUserMedia.call(
navigator,
constraints,
resolve,
reject
);
});
};
}
navigator.mediaDevices
.getUserMedia({ video: true })
.then( function (stream) {
player.srcObject = stream;
player.style.display = "block" ;
})
. catch ( function (err) {
console.log(err);
imagePicker.style.display = "block" ;
});
}
function takepic(event) {
canvas.style.display = "block" ;
player.style.display = "none" ;
capture.style.display = "none" ;
let context = canvas.getContext( "2d" );
context.drawImage(
player,
0,
0,
canvas.width,
player.videoHeight /
(player.videoWidth / canvas.width)
);
player.srcObject
.getVideoTracks()
.forEach( function (track) {
track.stop();
});
}
|
Step 11: Create a new file called feed.js in the (/src/public) folder. In feed.js, we use geolocation and mediaDevices to implement functionalities of location and camera respectively. You can also use the Google Geocoder API to convert these latitudes and longitudes into the name of a place.
Output: You can now navigate to localhost:3000/profile to take your picture and get the location.

Native Features Enabled
Explanation: Clicking on the Get Location button will trigger the navigator.geolocation.getCurrentPosition inside the handler function thereby populating the latitude and longitude fields with appropriate values. To get the exact name of the city, try using the Geocoder API as mentioned above. Similarly, clicking on the Take a Picture, Now Button will trigger the navigator.mediaDevices.getUserMedia inside the initializeMedia function thereby opening the front camera and taking a picture. Both these functions will first add for permissions and then execute themselves.
Similar Reads
How to Build a Progressive Web App (PWA) from Scratch?
A Progressive Web App (PWA) is a kind of application software sent through the web, formed using standard web technologies such as HTML, CSS, and JavaScript. PWAs are planned to work on any platform that uses a standards-compliant browser, containing both desktop and portable devices. Steps to Build
4 min read
How to Create a Basic Notes App using ReactJS ?
Creating a basic notes app using React JS is a better way to learn how to manage state, handle user input, and render components dynamically. In this article, we are going to learn how to create a basic notes app using React JS. A notes app is a digital application that allows users to create, manag
4 min read
How To Create A Multi-Page Website Using ReactJS?
Multi-page website using ReactJS is the core for building complex web applications that require multiple views or pages. Previously where each page reloads entirely, ReactJS allows you to navigate between different pages without reloading the whole page thanks to libraries like React Router. In this
4 min read
How to Deploy React App using Azure Static Web Apps ?
Microsoft Azure is a public cloud computing platform. It provides a lot of cloud services to access, manage, and deploy applications. Where as Azure Static Web App is one of the services of Microsoft Azure. It automatically builds and deploys full-stack web apps from the code repository to azure. In
3 min read
How to use events in ReactJS ?
Modern webpages rely on user interactions, triggering events like clicks or keypresses. React facilitates event handling with built-in methods, allowing developers to create listeners for dynamic interfaces and responses. JavaScript events, inherent to the DOM, use bubbling propagation by default, m
2 min read
Create ToDo App using ReactJS
In this article, we will create a to-do app to understand the basics of ReactJS. We will be working with class based components in this application and use the React-Bootstrap module to style the components. This to-do list can add new tasks we can also delete the tasks by clicking on them. The logi
3 min read
General Introduction to Progressive Web Apps(PWA)
What is an App? Must be findable in App Store Icons must be present on Home Screen Touch and Gesture Controls Works Offline Receives push notifications Background processing Access to hardware features and sensors What is the Web ? Contains URLs and Links Markup and styling that must be readable by
2 min read
How To Create a Website in ReactJS?
ReactJS is one of the most popular JavaScript libraries for building user interfaces. It allows you to create dynamic, reusable UI components and efficiently manage state and events. In this article, we'll walk through the steps to create a basic website using ReactJS. PrerequisitesNPM & Node.js
5 min read
How To Dockerize a ReactJS App?
Dockerizing a React app ensures that your application runs consistently across various environments by containerizing it. By creating a Docker container, you can package your React app, along with its dependencies, to ensure that it runs the same way regardless of the environment. In this article, w
4 min read
Create a Quiz App using ReactJS
In this article, we will create a quiz application to learn the basics of ReactJS. We will be using class components to create the application with custom and bootstrap styling. The application will start with questions at first and then the score will be displayed at last. Initially, there are only
4 min read