# Frontend Overview | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)

**Author:** Ndianabasi Udonkang  
**Published:** 2021-09-11

This lesson dives deep into how the UI of the Google Contacts clone app will be structured including details of how Vue Router works.

---

## Tags

- [JavaScript](/llms/technical-blog/tag/javascript.md)
- [Nodejs](/llms/technical-blog/tag/nodejs.md)
- [Vuejs](/llms/technical-blog/tag/vuejs.md)
- [Adonisjs](/llms/technical-blog/tag/adonisjs.md)
- [Quasar Framework](/llms/technical-blog/tag/quasar-framework.md)

## Part of Series: [Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)

This article is part of the **[Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)** series.

### Articles in this Series:

- [Introduction to Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vuejs (Quasar Framework)](/llms/technical-blog/article/xe5mlxg43s9rpx1pxsvfdp3r/introduction-to-full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vuejs-quasar-framework.md)
- [Workspace Setup | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fo8str8yjpkz5dygxg875bpw/workspace-setup-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- **Frontend Overview | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)** (Current Article)
- [The Left Drawer | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/m6fagvy2il5h65llxxbbl9os/the-left-drawer-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improve The Header | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/jjwbxcg450jmkkcrrmkmwvwj/improve-the-header-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [New Contact Form Design | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/ebguwpkntk3empakunrki4dq/new-contact-form-design-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Validating the Contact Form with Vuelidate | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/z0xr9m2ljler2cwnpsw2ycwa/validating-the-contact-form-with-vuelidate-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/h2p1x1z406ib38zu2dci3jur/designing-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table (Part 2) | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/j0iscua9gg8ekuz8ifh6chpn/designing-the-contacts-table-part-2-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Refactoring the Main Layout | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/uktmlqsivwtr3cvnpld59k9q/refactoring-the-main-layout-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improving User Experience with the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/dzs812auf61ej7qu2cg726dh/improving-user-experience-with-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contact Details Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/kf9pz97n63fvgfrcy5viwzrg/designing-the-contact-details-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Creating the Contact Edit Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fmr90prj84c9zn0633jc368g/creating-the-contact-edit-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [How Software Backends Work | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/aca8fcrghz70nn1wqg3uzbum/how-software-backends-work-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up The Backend | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fxb49fmz9ljbwrimbnnzudfv/setting-up-the-backend-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Why Choose the AdonisJs Framework? | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/lnhm5oudx34yo2869gmcms37/why-choose-the-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Our API Server with AdonisJs Framework | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/x1jgmet84aqj9qggu5mulkh0/setting-up-our-api-server-with-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Postman with the API Server | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/v4qehksislosmuy92qgjr4ct/setting-up-postman-with-the-api-server-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [The Model-View-Controller Design Pattern in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/h5wqql65iejop5xrplujw458/the-model-view-controller-design-pattern-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Create Column Definitions & Insert New Contacts | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/asc2emsho4u73r6jb2gxjddw/create-column-definitions-and-insert-new-contacts-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Data Validation & Sanitisation with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/bcey0ac7m5sbs9hqy1h824sl/data-validation-and-sanitisation-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Creating a Middleware and Updating a Contact | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/oqxzmtgfy1r3oewpnedc7wf6/creating-a-middleware-and-updating-a-contact-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Fetching and Deleting a Contact with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/p6bh0ponq43u3vi6o8uww84x/fetching-and-deleting-a-contact-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Using Model Factories and Seeders in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cfotveuxbgjtdp12l6pzcb2y/using-model-factories-and-seeders-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Creating and Registering a Vuex Module | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cw96ewnzujgsz2e2garhbuzb/creating-and-registering-a-vuex-module-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting UI Components to the Vuex Store | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fdyqp17yehbnqrjvjvab4b5b/connecting-ui-components-to-the-vuex-store-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting the Frontend to the API Server | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fk4262359gg3g7f0jn95fn9b/connecting-the-frontend-to-the-api-server-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Creating and Updating Contacts From the Frontend | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/t15w2s3ao9jo74l96stjo7z6/creating-and-updating-contacts-from-the-frontend-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Uploading Files and Creating Avatars for Contacts With AdonisJS and Axios](/llms/technical-blog/article/hg9ilaubqesm8angg0rhrjp9/uploading-files-and-creating-avatars-for-contacts-with-adonis-js-and-axios.md)
- [Deleting a Contact with AdonisJS and Vuejs](/llms/technical-blog/article/zdr4pxmgcax2dsfnwimhty0g/deleting-a-contact-with-adonis-js-and-vuejs.md)

---

## Article Content

In this lesson, you will gain a deeper understanding of how a Quasar UI is structured.

### Recommended reads

It is recommended that you read all layout-related pages on the official docs: [Layout](https://quasar.dev/layout/layout), [Layout Header and Footer](https://quasar.dev/layout/header-and-footer),  [Layout Drawer](https://quasar.dev/layout/drawer), [Layout Page](https://quasar.dev/layout/page), [Page Sticky](https://quasar.dev/layout/page-sticky), etc.

A Quasar UI project has a familiar structure for those who have used other Vue.js frameworks such as Nuxt. All code-related files you will be editing and creating are stored in `ui/src` folder. A full breakdown of the directories under `ui` can be found at: https://quasar.dev/quasar-cli/directory-structure.

You will begin by editing the content of the left drawer which can be toggled by clicking the menu button on the top-left corner of the window. It currently contains some placeholders. We want it to look like the image below:

![google-contacts-clone-target-left-drawer.png](https://cdn.ndianabasi.com/site/frontend_overview_full_stack_google_contacts_clone_with_adonis_js_node_js_and_quasar_vue_js_v1631316405040_5ge57_IT_4_V_010b6b07b5.png)

### Quasar Config

An important note to add is that the series will make use of material icons. You can them [here](https://jossef.github.io/material-design-icons-iconfont/). This is the default choice by the Quasar Framework. You can change to your own icon set in the file: `ui/quasar.conf.js`. This file is executed by the Quasar CLI in the Node.js environment, so you must have Node.js installed. You can read more about installing and using extra fonts and icons  [here](https://quasar.dev/options/installing-icon-libraries). You are read more about the configurations with the `ui/quasar.conf.jg`  [here](https://quasar.dev/quasar-cli/quasar-conf-js).

### Deep Dive into the (Quasar) Layout

The layout of the UI can be found in the `ui/src/layouts/MainLayout.vue` SFC (single-file component) file. The snapshot of the file at this point is  [found here](https://github.com/ndianabasi/google-contacts/blob/b04431aa5945adaaddc8776b7536c5faa7e6bf19/ui/src/layouts/MainLayout.vue#L1-L172). The template within the file starts with a `q-layout` component which wraps the entire template. Within the `q-layout` component are three important sections:

1. The Header (`q-header`),
2. The Drawer (`q-drawer`), and
3. The Page Container (`q-page-container`).

The  `q-header` component forms the top header of the layout. It will be constant for all views using this layout. It contains the toolbar (`q-toolbar`) which contains all the components you can see in the header. Look around and you will be logo, search input, and dropdown.

The `q-drawer` component forms the left drawer for the application. It is also constant for all views. Our drawer customisation will be done within this component.

The Page Container is equally very important. It determines all the content which will appear within the body of the layout. It also allows all the router views we want to display to be possible. That is why you see the `router-view` component within the `q-page-container` component. Typically, an application could have nested `router-view` components but there must be one at the top-level in the layout file as the entry point.

There is an example component displayed dead center without the page container. It shows a list of todo tasks (ct1 to ct5), count, active, and clicks on todos. If you click on any todo task, the clicks on todo will be incremented by 1. Where does it come from? It comes from the `router-view` component. How is this possible? The `router-view` is used to load any component which as assigned to the current route. In this case, the current route is `/` i.e. the entry route. You can see which component was assigned to the `/` route by examining the routes configuration in the router index file. Navigate to `ui/router/index.ts`. The snapshot of the index file at this point can be  [found here](https://github.com/ndianabasi/google-contacts/blob/b04431aa5945adaaddc8776b7536c5faa7e6bf19/ui/src/router/index.ts).

### More Gist About Vue Router and Routes

The router index file contains all configuration for Vue Router which is responsible for all navigations without the app. The line `import routes from "./routes";` imports the routes declaration into the index file. Navigate to `ui/router/routes.ts`. The snapshot of this file at this point is  [found here](https://github.com/ndianabasi/google-contacts/blob/b04431aa5945adaaddc8776b7536c5faa7e6bf19/ui/src/router/routes.ts). The `route.ts` file exports an array of route objects. There are currently two route objects. One with the path `"/"` and a `catchAll` route used for detecting 404 errors within your frontend navigations. Let's call the `"/"` path the `home` route going forward. The `home` route defines the the `ui/layouts/MainLayout.vue` layout file as the route component. This is how the MainLayout.vue is loaded for the first time, enabling the rendering of the entire layout of the application as described in the previously. Without this, our entire app will break. A route object call contain children route objects. Obviously, since this is the `home` route, the children route object will be used to load every other component into the app. In Vue Router, you can nest your route objects as deep as your application requires. You can see a demonstration in the [route file of the Akpoho Invoicing Software](https://github.com/ndianabasi/akpoho-invoicing-software/blob/30a0ac4cc106a9a429c51062013a18a6ed233228/frontend/src/router/routes.ts).

The children property of the `home` route contains one route object. This route object defines a path, `""`. The path is empty. Why? ***In Vue Router, when you define a path as empty, it implies that you want the component define in the route to appear when the path of the parent route is navigated to***. In this case, the parent route path is `/`, so the the component file, `ui/pages/Index.vue`, defined for this route will be loaded to replace the `router-view` component when you visit the path `/`.  [Snapshot of `ui/pages/Index.vue`](https://github.com/ndianabasi/google-contacts/blob/b04431aa5945adaaddc8776b7536c5faa7e6bf19/ui/src/pages/Index.vue) at this point. This will become clearer soon. Also study the  [route file of the Akpoho Invoicing Software](https://github.com/ndianabasi/akpoho-invoicing-software/blob/30a0ac4cc106a9a429c51062013a18a6ed233228/frontend/src/router/routes.ts) for lots of such implementations.

>

TIP: In a large app, your `route.ts` file can easily grow so long and difficult to navigate. Since it is a regular JavaScript file, you can group and extract some route objects into separate files and import them into the main `route.ts` file as done  [here](https://github.com/ndianabasi/akpoho-invoicing-software/blob/30a0ac4cc106a9a429c51062013a18a6ed233228/frontend/src/router/routes.ts).

Now, navigate to the `ui/pages/Index.vue` file and you will see the component responsible for the example component currently displayed in the center of the layout. This component will be replaced with a table for listing your contacts as seen in the home page of the desktop view of contacts.google.com.

I mentioned that the `routes.ts` file has a single route object for catching 404 errors. You should not remove that route object and it should always be the last because Vue Router will search through all our routes to find a match for the page you intend to visit. The moment Vue Router arrives at this route, `/:catchAll(.*)*`, it means that the page you intend navigating to is unavailable. The router will load the component file `ui/pages/Error404.vue` to show the 404 error page. Try it out by entering `http://localhost:8008/#/home`. The `/home` route is not defined, so that results in a 404 error.

### Structuring (Quasar) Pages

The `ui/pages/Index.vue` ([snapshot](https://github.com/ndianabasi/google-contacts/blob/b04431aa5945adaaddc8776b7536c5faa7e6bf19/ui/src/pages/Index.vue)) file contains a template which wraps a `q-page` component. The `q-page` component wraps the `example-component`. The `q-page` component from Quasar is used to define a new page. It indicates the beginning of the new page. Because of this, it should be the root component for every component file used for defining a page. When loaded via the `router-view`, it is become the direct child of the `q-page-container`. Read more  [here](https://quasar.dev/layout/page#usage).

```html
// From https://quasar.dev/layout/page#usage

<q-layout>
  ...
  <q-page-container>
    <q-page>
      <!-- page content -->
    </q-page>
  </q-page-container>
  ...
</q-layout>
```

In the next lesson, you will start the actual customisation of the UI beginning from the left drawer component.


*This document was generated from the live article page on https://ndianabasi.com/technical-blog/article/nxgmng6fhf1cwjk30coflro2/frontend-overview-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js • 2026-06-07*
