How do you Make React App a PWA ?
Last Updated :
23 Jul, 2025
Progressive Web Apps (PWAs) have emerged as a game-changer, offering a blend of website accessibility and native mobile app capabilities, thereby presenting the best of both worlds.
What is a Progressive Web App (PWA)?
Progressive Web Apps (PWAs) are web applications that offer a native app-like experience on the web. They are reliable, fast, and engaging, offering features such as offline access, push notifications, and home screen installation. In this article, we'll explore how to make a React application a PWA.
Key Features of PWA
- Offline capability: Works even without a network connection.
- App-like experience: Offers native-like navigation and interaction.
- Home screen installation: Users can install the app on their devices.
- Push notifications: Allows for re-engagement with users.
We will Create a simple React-based web application that fetches a list of popular movies from The Movie Database (TMDb) API and displays them in a user-friendly format. The app demonstrates basic concepts in React, including state management, component rendering, and API integration.
npx create-react-app pwa-application
cd pwa-application
Get TMDb API Key
Follow these steps to get an API key from TMDb:
- Create an account on TMDb.
- Go to "Settings" > "API" to generate your API key.
Enable HTTPS
Security is crucial for PWAs. Configure your web server to serve your app over HTTPs. Let's assume you have a mechanism in place (like a free SSL certificate from Let's Encrypt) to handle this.
Add a Web App Manifest (WAM): (manifest.json)
The WAM is a JSON file that provides essential information about your PWA, including its name, icons, theme color, and startup screen. Create a file named manifest.json at the root of your project directory and add the following content, customizing it for your app:
This JSON file provides metadata about your PWA, including its name, icons, and installation behavior on the home screen
public->manifest.json
manifest.json
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "maskable_icon_x192.png",
"type": "image/png",
"sizes": "192x192",
"purpose":"any maskable"
},
{
"src": "maskable_icon_x192.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
Register a Service Worker:(optional, but recommended for core PWA features)
A service worker is a script that runs in the background, enabling functionalities like offline access, push notifications, and background sync. Create a file named serviceWorker.js in your public directory and add the following code:
public->index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://web.dev/articles/add-manifest
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script>
if('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./serviceWorker.js').then((reg) => {
console.log('Worker Registered')
}).catch((err) => {
console.log('Error in service worker registration.')
})
})
}
</script>
</body>
</html>
Implementing Offline Functionality
Service Worker Caching: Utilize the Service Worker Caching API to cache static assets like HTML, CSS, JavaScript, and images.
Now inside the public create serviceWorker.js
//STORAGE OF BROWSER
const CACHE_NAME = "version-1";
const urlsToCache = ["index.html", "offline.html"];
const self = this;
//installation
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log("Opened cache");
return cache.addAll(urlsToCache);
})
);
});
// listen for request
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((res) => {
return fetch(event.request).catch(() => caches.match("offline.html"));
})
);
});
// actitivate the service worker
self.addEventListener("activate", (event) => {
const cacheWhitelist = [];
cacheWhitelist.push(CACHE_NAME);
event.waitUntil(
caches.keys().then((cacheNames) => Promise.all(
cacheNames.map((cacheName) => {
if(!cacheWhitelist.includes(cacheName)){
return caches.delete(cacheName);
}
})
))
)
});
Register the Service Worker (index.js)
In your src/index.js file, import and register the service worker:
JavaScript
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// Import the service worker file
import * as serviceWorkerRegistration from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// Register the service worker (with optional delay)
serviceWorkerRegistration.register({
onUpdate: (registration) => {
const confirmationMessage =
`New update is available. Click OK to reload.`;
if (confirm(confirmationMessage)) {
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
}
},
});
// If you want to delay service worker registration (optional)
// serviceWorkerRegistration.register({
// delay: 10000, // Delay by 10 seconds
// });
// If you want to register the service
// worker only in production (optional)
// if (process.env.NODE_ENV === 'production') {
// serviceWorkerRegistration.register();
// }
reportWebVitals();
Enabling Push Notifications (Optional)
Push notifications are a powerful way to re-engage users and keep them informed even when they're not actively using your app. By implementing push notifications in your React PWA with Firebase Cloud Messaging (FCM), you can:
- Send real-time updates and messages to users.
- Increase user engagement and retention.
- Promote new features or content.
- Drive traffic back to your PWA.
Steps to Create a React App
Step 1: Create a React application using the following command:
npx create-react-app pwa-application
Step 2: After creating your project folder i.e. foldername, move to it using the following command:
cd pwa-application
Step 3: Install the required dependencies in your project using the following command:
npm install axios
Project Structure:
Project Structure: The updated dependencies in your packge.json file is:
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"axios": "^1.6.7",
},
CSS
/* App.css */
.app-container {
padding: 20px;
}
.movie-list {
list-style: none;
padding: 0;
}
.movie-item {
margin-bottom: 20px;
display: flex;
align-items: center;
}
.movie-poster {
margin-right: 10px;
width: 100px;
/* Set a fixed width for the poster images */
height: auto;
/* Maintain aspect ratio */
}
JavaScript
//App.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import './App.css';
const API_KEY = 'paste your api key here';
const MOVIE_API_URL = `https://api.themoviedb.org/3/movie/popular?api_key=$%7BAPI_KEY%7D&language=en-US&page=1%60;
const BASE_IMAGE_URL = 'https://image.tmdb.org/t/p/w200';
function App() {
const [movies, setMovies] = useState([]);
useEffect(() => {
axios.get(MOVIE_API_URL)
.then((response) => {
setMovies(response.data.results);
})
.catch((error) => {
console.error('Error fetching the movies:', error);
});
}, []);
return (
<div className="app-container">
<h1>Popular Movies</h1>
<ul className="movie-list">
{movies.map((movie) => (
<li key={movie.id} className="movie-item">
<img
src={`${BASE_IMAGE_URL}${movie.poster_path}`}
alt={movie.title}
className="movie-poster"
/>
<strong>{movie.title}</strong>
(Release Date: {movie.release_date})
</li>
))}
</ul>
</div>
);
}
export default App;
JavaScript
// serviceWorker.js
//STORAGE OF BROWSER
const CACHE_NAME = "version-1";
const urlsToCache = ["index.html", "offline.html"];
const self = this;
//installation
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log("Opened cache");
return cache.addAll(urlsToCache);
})
);
});
// listen for request
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((res) => {
return fetch(event.request).catch(() => caches.match("offline.html"));
})
);
});
// actitivate the service worker
self.addEventListener("activate", (event) => {
const cacheWhitelist = [];
cacheWhitelist.push(CACHE_NAME);
event.waitUntil(
caches.keys().then((cacheNames) => Promise.all(
cacheNames.map((cacheName) => {
if(!cacheWhitelist.includes(cacheName)){
return caches.delete(cacheName);
}
})
))
)
});
Start your application using the following command:
npm start
Output:
Final outputConclusion
By following these steps, you've converted the "Movie List Application" into a Progressive Web App. This PWA has a service worker for offline support, a manifest file for metadata and icons, and HTTPS for security. It's installable on users' devices and works even when offline, providing a more engaging user experience.
Similar Reads
React Tutorial React is a powerful JavaScript library for building fast, scalable front-end applications. Created by Facebook, it's known for its component-based structure, single-page applications (SPAs), and virtual DOM,enabling efficient UI updates and a seamless user experience.Note: The latest stable version
7 min read
React Fundamentals
React IntroductionReactJS is a component-based JavaScript library used to build dynamic and interactive user interfaces. It simplifies the creation of single-page applications (SPAs) with a focus on performance and maintainability. "Hello, World!" Program in ReactJavaScriptimport React from 'react'; function App() {
6 min read
React Environment SetupTo run any React application, we need to first setup a ReactJS Development Environment. In this article, we will show you a step-by-step guide to installing and configuring a working React development environment.Pre-requisite:We must have Nodejs installed on our PC. So, the very first step will be
3 min read
React JS ReactDOMReactDOM is a core React package that provides DOM-specific methods to interact with and manipulate the Document Object Model (DOM), enabling efficient rendering and management of web page elements. ReactDOM is used for: Rendering Components: Displays React components in the DOM.DOM Manipulation: Al
2 min read
React JSXJSX stands for JavaScript XML, and it is a special syntax used in React to simplify building user interfaces. JSX allows you to write HTML-like code directly inside JavaScript, enabling you to create UI components more efficiently. Although JSX looks like regular HTML, itâs actually a syntax extensi
5 min read
ReactJS Rendering ElementsIn this article we will learn about rendering elements in ReactJS, updating the rendered elements and will also discuss about how efficiently the elements are rendered.What are React Elements?React elements are the smallest building blocks of a React application. They are different from DOM elements
3 min read
React ListsIn lists, React makes it easier to render multiple elements dynamically from arrays or objects, ensuring efficient and reusable code. Since nearly 85% of React projects involve displaying data collectionsâlike user profiles, product catalogs, or tasksâunderstanding how to work with lists.To render a
4 min read
React FormsForms are an essential part of any application used for collecting user data, processing payments, or handling authentication. React Forms are the components used to collect and manage the user inputs. These components include the input elements like text field, check box, date input, dropdowns etc.
5 min read
ReactJS KeysA key serves as a unique identifier in React, helping to track which items in a list have changed, been updated, or removed. It is particularly useful when dynamically creating components or when users modify the list. When rendering a list, you need to assign a unique key prop to each element in th
4 min read
Components in React
React Lifecycle In React, the lifecycle refers to the various stages a component goes through. These stages allow developers to run specific code at key moments, such as when the component is created, updated, or removed. By understanding the React lifecycle, you can better manage resources, side effects, and perfo
7 min read
React Hooks
Routing in React
Advanced React Concepts
React Projects