- Building a Mobile App using HTML, CSS, and JavaScript
- What are Progressive Web Apps?
- Structuring Our HTML
- Styling our app with CSS
- Open Source Session Replay
- Setting up Dexie.js to work with IndexedDB
- Setting up Workbox
- Making App Installable
- Testing App on a Mobile Device
- Conclusion
- Resources
- More articles from OpenReplay Blog
- The Software Testing Life Cycle
- Solid vs React — the Fastest VS the Most Popular UI Library
- Gain Debugging Superpowers
Building a Mobile App using HTML, CSS, and JavaScript
So you have seen the title, and you are wondering how you can pull off building an actual mobile application by just using the knowledge of basic web technologies without the need to learn Android or IOS development? This is made possible by converting your regular web applications to work as a standard mobile application that can be installed on multiple platforms. By doing this, we will achieve a type of application referred to as Progressive Web Apps (PWAs). In this article, we will learn how to leverage the power of HTML, CSS, and Javascript to build a simple mobile app. We will not be using frameworks like Ionic or React Native. This is because this tutorial focuses on showing how a basic web app can be made to feel and behave like a native mobile application that can be installed and run on mobile devices using the most straightforward method with the least abstraction. To proceed, let us have a brief introduction to PWAs.
What are Progressive Web Apps?
Progressive Web Apps (PWAs) are web apps that use service workers, manifests, and other web-platform features combined with progressive enhancement to give users an experience on par with native apps.
- Service Worker: The service worker transforms the website into an app by allowing it to download and cache files on a device.
- ** Web Manifest:** This JSON file provides the basic meta-information about the app, such as the app icon, background color, etc.
- Secure HTTPS: HTTPS is mandatory and makes PWAs more secure than regular web apps.
PWAs have pros and cons. Among the former:
- Cheap and Fast Development: PWAs are less expensive, quicker, and easier to create than native apps. Native app development from the ground up necessitates particular technologies for both platforms. HTML, CSS, and JavaScript are all that are required for a PWA.
- Cross-Platform Availability: One of the promising advantages of PWAs is that they can be installed and run on multiple devices across various operating systems.
- Offline Functionality: Having bad or no internet at all won’t stop users from using your app as it can cache data for offline viewing using service workers.
- Performance: Compared to native mobile apps, PWAs are much lighter, don’t take as much memory space, and have a faster load time.
- High Battery Usage: Because PWAs are built-in high-level web code, phones have to work harder to read the code; they use more battery than native apps.
- Mobile hardware access: PWAs cannot access various hardware features like the device’s Bluetooth, proximity sensors, etc.
- Distribution Since PWAs are not distributed through the app store, you may miss out on users who mainly browse the app store.
You should consider using/building Progressive Web Apps if you meet the following criteria:
- You don’t have the budget to build a full-fledged app.
- You need to push to your target audience faster.
- Having cross-platform compatibility is essential to your business.
We’ll be building a “Todo List” mobile app using HTML, CSS, and Javascript. We will first build out a web app while using IndexedDB for our database, workbox to make it work offline, and web manifest to make it installable across devices. The final result will be as follows:
We start by creating an empty folder called Todo App and then create three files inside called index.html , index.css , index.js , and the assets folder(which will contain our logo).
Structuring Our HTML
Go to the index.html file and enter the following lines of code:
Todo PWA
Tasks
Here, we created our HTML page layout and linked both our index.css and index.js . Now let’s move on and add some styling.
Styling our app with CSS
Update the index.css file with the code below:
:root --dark: #05152E; --darker: #1F2937; --darkest: #001E3C; --grey: #6B7280; --pink: #EC4899; --purple: #8B5CF6; --light: #EEE; > * margin: 0; box-sizing: border-box; font-family: "Fira sans", sans-serif; > body display: flex; flex-direction: column; min-height: 100vh; color: #FFF; background-color: var(--dark); > header padding: 2rem 1rem; max-width: 800px; width: 100%; margin: 0 auto; > header h1 font-size: 2.5rem; font-weight: 300; color: white; margin-bottom: 1rem; > h1 text-align: center; > #new-task-form display: flex; > input, button appearance: none; border: none; outline: none; background: none; > #new-task-input flex: 1 1 0%; background-color: var(--darker); padding: 1rem; border-radius: 1rem; margin-right: 1rem; color: var(--light); font-size: 1.25rem; > #new-task-input::placeholder color: var(--grey); > #new-task-submit color: var(--pink); font-size: 1.25rem; font-weight: 700; background-image: linear-gradient(to right, var(--pink), var(--purple)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; cursor: pointer; transition: 0.4s; > #new-task-submit:hover opacity: 0.8; > #new-task-submit:active opacity: 0.6; > main flex: 1 1 0%; max-width: 800px; width: 100%; margin: 0 auto; > .task-list padding: 1rem; > .task-list h2 font-size: 1.5rem; font-weight: 300; color: var(--grey); margin-bottom: 1rem; > #tasks .task display: flex; justify-content: space-between; background-color: var(--darkest); padding: 1rem; border-radius: 1rem; margin-bottom: 1rem; > .task .content flex: 1 1 0%; > .task .content .text color: var(--light); font-size: 1.125rem; width: 100%; display: block; transition: 0.4s; > .task .content .text:not(:read-only) color: var(--pink); > .task .actions display: flex; margin: 0 -0.5rem; > .task .actions button cursor: pointer; margin: 0 0.5rem; font-size: 1.125rem; font-weight: 700; text-transform: uppercase; transition: 0.4s; > .task .actions button:hover opacity: 0.8; > .task .actions button:active opacity: 0.6; > .task .actions .edit background-image: linear-gradient(to right, var(--pink), var(--purple)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; > .task .actions .delete color: crimson; >
Open Source Session Replay
OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.
Setting up Dexie.js to work with IndexedDB
Let’s move on to our Javascript file. But first, let’s configure our IndexedDB database, a database in the browser that will store all our todos.
Note: This is not local storage but an actual database located in the browser.
To interact with this database, we will need to install Dexie.js , a wrapper around IndexedDB that will help us manage our database with ease. Go to dexie.js documentation and download the script file. Add the following to your head tag in index.html .
Then in the index.js file, we initialize a new database using Dexie.js .
//creating database structure const db = new Dexie("Todo App"); db.version(1).stores(< todos: "++id, todo" >); const form = document.querySelector("#new-task-form"); const input = document.querySelector("#new-task-input"); const list_el = document.querySelector("#tasks"); //add todo form.onsubmit = async (event) => event.preventDefault(); const todo = input.value; await db.todos.add(< todo >); await getTodos(); form.reset(); >; //display todo const getTodos = async () => const allTodos = await db.todos.reverse().toArray(); list_el.innerHTML = allTodos .map( (todo) => ` todo.todo>> .id>)">Delete ` ) .join(""); >; window.onload = getTodos; //delete todo const deleteTodo = async (event, id) => await db.todos.delete(id); await getTodos(); >;
In the above code sample, we implemented the basic functions our app should have. We can add, display and delete todos from our database. Now that we have our basic app setup, it’s time to focus on what will make our app behave like a typical mobile application. First, we will make our application have offline functionality, which will enable it to work without an internet connection.
Setting up Workbox
Google workbox is the tool that will generate service workers, which will make our app work without an internet connection. First, let’s install workbox globally on our machine. Run:
npm install Workboxcli --global
Then to configure our workbox, run:
In the console, you will be asked to register the root path of your application. Select Manually enter path, then use ./ as the root path.
Then, select cache all files. Also, agree to the save for service worker and config, and lastly select no for the last option.
After this, we will see that a file called workbox-config.js has been created. Immediately after this, run this command to generate the service worker.
workbox generateSW workbox-config.js
Now add this code below to the head tag of the HTML file. It will register the service worker when the window is loaded.
script> // Check that service workers are supported if ("serviceWorker" in navigator) // Use the window load event to keep the page load performant window.addEventListener("load", () => navigator.serviceWorker.register("./sw.js"); >); > script>
Go to your browser, right-click and click inspect, and then navigate to applications and locate the service worker. You will see that the service worker is already running.
Before we continue, push your code to your GitHub repo and host it. For this article, I am hosting with GitHub pages.
Making App Installable
We have to add a web manifest to our app to achieve this. This is a JSON file that will host necessary details of our app, such as the logo, app name, description, and so on. Go to the root of the app folder and create manifest.json . Then add this code below:
name: "Todo PWA", short_name: "Todo", icons: [ src: "./assets/icon-100.png", sizes: "100x100", type: "image/png", >, src: "./assets/icon-150.png", sizes: "150x150", type: "image/png", >, src: "./assets/icon-250.png", sizes: "250x250", type: "image/png", >, src: "./assets/icon-500.png", sizes: "500x500", type: "image/png", >, ], theme_color: "#FFFFFF", background_color: "#FFFFFF", start_url: "/PWA-TodoApp/", display: "standalone", orientation: "portrait", >;
Then add the link to the manifest file to the head of our index.html file. Now push these changes to your repo.
Testing App on a Mobile Device
Finally, we have completed our Mobile application just by using HTML, CSS, and Javascript. Go ahead and visit your hosted URL and install your app on your mobile device.
Conclusion
Congrats! on making it here. You have learned how to set up mobile apps using your knowledge of basic web technologies and an overview of PWAs. You can go further and expand your knowledge by making use of other frameworks to help you add more capabilities to your application.
If you have any questions, please reach out on Twitter.
Resources
More articles from OpenReplay Blog
The Software Testing Life Cycle
Solid vs React — the Fastest VS the Most Popular UI Library
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs and track frustrations in your app. Get complete visibility into your frontend with OpenReplay, the most advanced open-source session replay tool for developers.