Creating Gojek Clone For Beginners Using Tailwind CSS

5/5 - (2 votes)

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.

Setup Development Environment

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!

Design the Homepage

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.

Add Ride Booking Section

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.

Food Delivery Section

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.

Add Payments Section

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.

Add User Profile Section

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="

Add Sidebar Menu

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.

Build Individual Pages

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.

Add Basic Routing

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.

Responsiveness with Media Queries

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.

Deploy to GitHub Pages

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.

Final Words

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.

Prasad Venkatachalam

Prasad Venkatachalam works in digital marketing at Zipprr. He loves technology and new ideas. He writes about tech and business in a clear and easy-to-understand way. He does a lot of research to make sure his writing is accurate and informative.