Creating Gojek Clone For Beginners Using Tailwind CSS

In this tutorial, we will go through the process of building a simple clone of the Gojek app for multi-service transportation network companies. Gojek allows users to book rides, order food delivery, make payments and more – we will focus on recreating the core user interface and functionality.
We will be using Tailwind CSS, a utility-first CSS framework, which is perfect for beginners because it allows building user interfaces without having to learn extensive CSS. By the end, you’ll have a working Gojek clone app that you can expand further.
The first step is to install the required tools and set up our project files. We will be using Node.js and NPM for managing dependencies and building the project.
Open your terminal and check if Node.js is installed by running node -v
. If not installed, download it from nodejs.org. We also need to install NPM by running npm install npm@latest -g
.
Now let’s create our project folder and navigate into it:
mkdir gojek-clone
cd gojek-clone
Inside this folder, initialize an NPM project with npm init -y
to generate a package.json file.
Next, install Tailwind CSS using the CLI tool:
npm install -D tailwindcss postcss autoprefixer
Create an index.html file and linked Tailwind’s CSS:
<link href="tailwind.css" rel="stylesheet">
We’re all set to start building our interface with Tailwind!
Let’s design the homepage where users can see featured services. We’ll add basic HTML structure:
<header>...</header>
<main>
<section class="banner">
</section>
<section class="features">
</section>
</main>
For the banner, we add an image and title:
<section class="banner bg-cover bg-center h-96">
<div class="text-center text-white py-20">
<h1 class="text-4xl font-bold">Your ride is one tap away</h1>
</div>
</section>
And customize it with Tailwind classes.
Now for the features section, we’ll add sample data:
const features = [
{
name: 'Rides',
icon: 'taxi'
},
{
name: 'Food',
icon: 'burger'
}
]
Loop through it to display cards:
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
{{features.map(feature => `
<div class="p-8 bg-white rounded-lg shadow-xl">
<img class="mx-auto" src=${feature.icon}>
<h2 class="text-2xl my-4">${feature.name}</h2>
</div>
`)}}
</div>
This displays the Homepage structure and sample content. We’ll keep improving the design.
Now let’s build the Ride Booking section. We’ll display a list of available rides:
// ride data
const rides = [
{
name: 'Go Car',
img: 'car.png',
pickup: 'ABC St',
dropoff: 'XYZ Rd',
time: '30 mins',
price: '$20'
},
// more rides
]
Add the section:
<section class="my-10">
<h2 class="text-3xl font-bold mb-6">
Available Rides
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
{{rides.map(ride => `
<div class="p-6 bg-white rounded-lg shadow-md">
<img class="w-20 mb-4" src=${ride.img}>
<div class="flex justify-between">
<h3 class="text-xl">${ride.name}</h3>
<button class="px-4 py-2 rounded bg-blue-500 text-white">
Book
</button>
</div>
<p class="text-gray-600 mb-2">
${ride.pickup} to ${ride.dropoff}
</p>
<p>${ride.time} - ${ride.price}</p>
</div>
`)}}
</div>
</section>
This dynamically maps over rides data and displays each one. We’ve added basic styling with Tailwind classes.
Next up is the Food Delivery section. The process will be similar – we define sample foods data:
const foods = [
{
name: 'Burger',
img: 'burger.jpg',
restaurant: 'Burger King',
rating: 4.5,
price: '$10'
},
// more foods
]
And display it:
<section class="my-10">
<h2 class="text-3xl font-bold mb-6">
Delicious Foods
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
{{foods.map(food => `
<div class="p-6 bg-white rounded-lg shadow-md">
<img class="w-20 mb-4" src=${food.img}>
<h3 class="text-xl">${food.name}</h3>
<p class="text-gray-600 mb-2">
From ${food.restaurant}
</p>
<div class="flex items-center mb-2">
<img src="star.svg">
<span class="text-yellow-500 ml-1">
${food.rating}
</span>
</div>
<p>${food.price}</p>
<button class="px-4 py-2 rounded bg-blue-500 text-white mt-4">
Order
</button>
</div>
`)}}
</div>
</section>
Again, we’ve defined the HTML structure and mapped over the foods data to dynamically populate the list.
Next up is adding a payments section where users can store and choose payment methods.
Let’s start with some sample payment data:
const payments = [
{
name: 'Credit Card',
img: 'card.png'
},
{
name: 'GoPay',
img: 'gopay.png'
},
{
name: 'Cash',
img: 'cash.png'
}
]
Now define the section:
<section class="my-10">
<h2 class="text-3xl font-bold mb-6">
Payment Methods
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
{{payments.map(payment => `
<div
class="flex items-center p-6 rounded-lg bg-gray-100">
<img
class="w-16 mr-4"
src=${payment.img}>
<p class="text-lg font-bold">
${payment.name}
</p>
</div>
`)}}
</div>
</section>
This will display the available payment options from the data.
We can also add a “Add Payment” button to allow users to store new cards/accounts later.
The profile section allows users to see their details and account settings.
Let’s define a sample user object:
const user = {
name: 'John Doe',
photo: 'user.jpg',
email: 'john@email.com'
}
Then add the profile dropdown:
<div class="relative">
<button
class="p-2 rounded-full bg-gray-100">
<img
class="w-10 rounded-full"
src=${user.photo}>
</button>
<div
class="absolute top-12 right-0 z-10 hidden
w-48 bg-white rounded-lg shadow-md
transition duration-200
transform translate-y-2
"
>
<div class="flex items-center p-4 border-b">
<img class="
To navigate between pages, let’s add a persistent sidebar menu.
First add the HTML:
<div
class="fixed top-0 left-0 z-20 w-64
bg-white h-screen overflow-y-auto
shadow-xl transition-all"
:class="{ '-translate-x-full': isMenuOpen == false }"
>
<div class="flex items-center h-16 pl-6">
<img src="logo.png">
</div>
<nav>
<a
href="#"
class="flex items-center py-4 px-6 hover:bg-gray-100">
<svg class="w-6 h-6 mr-3" ...>Home</svg>
Home
</a>
// other links
</nav>
</div>
Define a isMenuOpen
variable and toggle class to open/close.
Add method to app.js:
methods: {
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen
}
}
Link it to a menu button:
<button @click="toggleMenu">
<svg class="w-6 h-6" ...>Menu</svg>
</button>
Now users can easily navigate pages via the responsive sidebar menu.
With the common layout and navigation defined, let’s build the content pages:
Rides Page
<div class="rides-page">
<h1 class="text-3xl mb-8">Available Rides</h1>
<div class="rides-list">
<!-- rides component -->
</div>
</div>
Foods Page
<div class="foods-page">
<h1 class="text-3xl mb-8">Delicious Foods</h1>
<div class="foods-list">
<!-- foods component -->
</div>
</div>
Define reusable components:
<template id="rides">
<!-- ride card template -->
</template>
<template id="foods">
<!-- food card template -->
</template>
Import and render them:
// RidesPage.js
import Rides from './Rides.vue'
export default {
components: {
Rides
}
}
Now each page has a common structure and dynamically loads content.
To link pages together, let’s use Vue Router. Install it:
npm install vue-router
Define routes:
// router.js
import VueRouter from 'vue-router'
const routes = [
{
path: '/rides',
component: RidesPage
},
{
path: '/foods',
component: FoodsPage
}
]
export default new VueRouter({
routes
})
Register router in main app:
// main.js
import router from './router'
new Vue({
router
}).$mount('#app')
Now we can add router-links to menu:
<router-link to="/rides">Rides</router-link>
And route outlets in App component:
<router-view></router-view>
This provides basic navigation between static pages.
Let’s improve responsiveness for different screen sizes.
We can add Tailwind breakpoints and media queries:
<div
class="flex flex-col lg:flex-row">
<aside class="lg:w-1/4">...</aside>
<main class="lg:w-3/4">...</main>
</div>
For small screens:
@media (max-width: 768px) {
aside, main {
width: 100%;
}
}
Mobile navigation:
<div class="md:hidden">
<!-- mobile menu -->
</div>
<div class="hidden md:block">
<!-- desktop menu -->
</div>
Responsively stack/grid sections:
<div
class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- content -->
</div>
This makes the UI gracefully adapt different viewports.
Once the app was fully built, the next step was deploying it so it can be accessed online. GitHub Pages was used as it provides free hosting for websites directly from a GitHub repository.
The first part of deployment involved initializing a Git repository locally and uploading the project files and code to a new repository on GitHub. This allowed version controlling the project and having a remote code storage on the cloud.
After the repository was created, the gh-pages package was installed to help with deployment handling. It integrates with GitHub Pages specifications.
Next, a deploy script was added to the package configuration to automate the publishing process. It was set to output the built files to a specific folder.
The app code was then built into static files for production using a build command. All JavaScript, CSS and other assets were bundled and optimized.
Running the deploy script triggered GitHub Pages to pull the latest version from the repository. It recognizes the output folder as the deployment location.
From then on, any new commits to the main branch would automatically update the live deployment. Developers can easily push code changes which get reflected online instantly through the GitHub Pages hosting.
This provided a simple, yet powerful workflow to ship the Gojek clone from local development to a public URL through GitHub repositories. Deployments were fully integrated within the existing Git and code management processes.
In this tutorial, we’ve seen the process of building a basic Gojek clone application to emulate its main features like transportation rides, food delivery and payments.
We started with setting up the necessary development tools and creating the initial project files. Then we moved on to designing individual sections and pages through HTML and Tailwind CSS utilities.
Overall, this project provided an introduction to fundamental frontend development practices. Key learnings included setup, design methodologies, routing, data handling and deployment – valuable skills for beginners starting out with applications.
Monacgo: 7/1253 Subramania Siva Street, NGO colony, Nagamalaipudukottai, Madurai – 625019, Tamil Nadu, India.
Mobile: +91 6380757660
Monacgo: 403 Starkweather Ave, Cleveland, OH 44113, United States
Mobile: +1 (585) 632-0256
Email: support@zipprr.com
Disclaimer: The keywords Gojek, Airbnb, Uber, UberEats, UrbanClap, Amazon, Carousell, ChatGPT, Youtube, Facebook, Turo, Practo, TaskRabbit, TikTok, Udemy, Whatsapp, Tinder and Letgo are solely used for marketing purposes, and we are not associated with any of the mentioned companies in any form. The source code and design of our products are fully owned by sellers. We are not using any of their copyrighted materials.
© 2025 Zipprr. All rights reserved.