Black Friday: coupon FRIDAY24 for 40% off Yearly/Lifetime membership! Read more here
Courses

Vue.js 3 Client Parking App: Step-by-Step

Registration Page

In this lesson, we are going to create a Register page, make some app layouts, and, add routes with links.

Register page

1. Register page template

First, create a new Vue component src/views/Auth/RegisterView.vue

<template>
<form @submit.prevent="() => {}" novalidate>
<div class="flex flex-col mx-auto md:w-96 w-full">
<h1 class="text-2xl font-bold mb-4 text-center">Register</h1>
<div class="flex flex-col gap-2 mb-4">
<label for="name" class="required">Name</label>
<input
id="name"
name="name"
type="text"
class="form-input"
autocomplete="name"
required
/>
</div>
 
<div class="flex flex-col gap-2 mb-4">
<label for="email" class="required">Email</label>
<input
id="email"
name="email"
type="email"
class="form-input"
autocomplete="email"
required
/>
</div>
 
<div class="flex flex-col gap-2 mb-4">
<label for="password" class="required">Password</label>
<input
id="password"
name="password"
type="password"
class="form-input"
autocomplete="new-password"
required
/>
</div>
 
<div class="flex flex-col gap-2">
<label for="password_confirmation" class="required">
Confirm password
</label>
<input
id="password_confirmation"
name="password_confirmation"
type="password"
class="form-input"
autocomplete="new-password"
required
/>
</div>
 
<div class="border-t h-[1px] my-6"></div>
 
<div class="flex flex-col gap-2">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</div>
</form>
</template>

This is an ordinary form to display our registration form. There are a few things I'd like to address. The form has @submit.prevent which means when we submit the form vue prevents its default behavior, otherwise, the page would just reload, so we do not want that. The value of @submit.prevent is a callback or a function that will be called when you submit the form, in this case, it is just an empty function and will be implemented in later lessons. novalidate attribute tells the browser not to attempt any field validation by default, because we will implement validation to be done by the server every time the form is submitted.

<form @submit.prevent="() => {}" novalidate>

Another not-so-important but rather convenient thing for users is autocomplete attributes on form fields. It defines what type of values can be auto-filled by the browser or for example password managers to generate a new password if the user uses any. More information can be found there # HTML attribute: autocomplete.

We also added our classes to style repetitive HTML tags such as input, label, and button. There is only one button now, but we will have more of them in the future. So let's define those classes and apply tailwind styles for them in src/assets/main.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;
 
@layer components {
label.required {
@apply before:text-red-600 before:content-['*'] before:mr-1;
}
 
.form-input {
@apply p-1 border bg-gray-100 disabled:opacity-50;
}
 
.btn {
@apply inline-flex items-center gap-2 justify-center p-2 font-bold relative disabled:!opacity-50 disabled:!cursor-progress;
}
 
.btn-primary {
@apply text-white bg-blue-600 hover:bg-blue-500;
}
}

2. Define /register route

To be able to view that form, we need to register the route and the view for a component. Define the route with the following content in src/router/index.js file routes array:

{
path: "/register",
name: "register",
component: () => import("@/views/Auth/RegisterView.vue"),
},
  • path - the URL your app visitor will see in the browser
  • name - is the name of your route and also can be called a reference, so if you later decide to change path, you don't need to update the path in all your components.
  • component - accepts component or function which returns component. We chose to define an anonymous function that returns imported RegisterView. This generates a separate chunk (small js file) for this route which is lazy-loaded when the route is visited.

Instead of using the relative path ../views/Auth/RegisterView.vue we wrote it like that @/views/Auth/RegisterView.vue. The @ symbol is an alias to the src directory defined in the vite.config.js file. This has an advantage over relative paths because you don't need to update import statements if you decide to move a file containing these references to another folder.

3. Update the parent template

Now we can update the src/App.vue file by adding a navigation bar to switch between HomeView and RegisterView:

<script setup>
import { RouterLink, RouterView } from "vue-router";
</script>
 
<template>
<header class="py-6 bg-gray-100 shadow">
<div class="container md:px-2 px-4 mx-auto">
<nav class="flex gap-4 justify-between">
<div class="flex gap-4 items-center">
<h2 class="text-xl font-bold">
<div
class="inline-flex items-center justify-center bg-blue-600 w-6 h-6 text-center text-white rounded"
>
P
</div>
myParking
</h2>
<RouterLink class="router-link" :to="{ name: 'home' }">
Home
</RouterLink>
</div>
<div class="flex gap-4 items-center">
<RouterLink class="router-link" :to="{ name: 'register' }">
Register
</RouterLink>
</div>
</nav>
</div>
</header>
 
<div class="container md:px-2 px-4 pt-8 md:pt-16 mx-auto">
<RouterView />
</div>
</template>

Instead of hardcoding URLs like before <RouterLink to="/">Home</RouterLink> we use named routes like that:

<RouterLink class="router-link" :to="{ name: 'register' }">
Register
</RouterLink>

And finally, let's add our .router-link CSS class into the components section of the src/assets/main.css file:

.router-link {
@apply text-blue-600 hover:underline;
}
 
.router-link-active.router-link {
@apply underline;
}

The final result with working navigation should look like this:

Register page

avatar

I am following the tutorial step by step, but getting below error.

[plugin:vite:css] [postcss] E:/vue/Car-Parking/src/assets/main.css:7:5: The before: class does not exist. If before: is a custom class, make sure it is defined within a @layer directive. E:/vue/Car-Parking/src/assets/main.css:7:5 5 | @layer components { 6 | label.required { 7 | @apply before: text-red-600 before:content-['*'] before:mr-1; | ^ 8 | }

avatar

It should be as follows: https://github.com/LaravelDaily/Vue-Car-Parking-App-Demo/blob/main/src/assets/main.css

avatar

I have replaced content of main.css from https://github.com/LaravelDaily/Vue-Car-Parking-App-Demo/blob/main/src/assets/main.css.

However error is remained as it is.

avatar

Removed extra space after colon : and the error is resolved. Thanks David :)

avatar

How to eliminate below warning :

VITE v4.3.2 ready in 393 ms

➜ Local: http://127.0.0.1:5173/ ➜ Network: use --host to expose ➜ press h to show help

warn - As of Tailwind CSS v2.2, lightBlue has been renamed to sky. warn - Update your configuration file to silence this warning.

warn - As of Tailwind CSS v3.0, warmGray has been renamed to stone. warn - Update your configuration file to silence this warning.

warn - As of Tailwind CSS v3.0, trueGray has been renamed to neutral. warn - Update your configuration file to silence this warning.

warn - As of Tailwind CSS v3.0, coolGray has been renamed to gray. warn - Update your configuration file to silence this warning.

warn - As of Tailwind CSS v3.0, blueGray has been renamed to slate. warn - Update your configuration file to silence this warning.

avatar

I have googled your issue and here's the solution I found out: https://github.com/tailwindlabs/tailwindcss/issues/4690#issuecomment-1046087220

avatar

Thanks Sir, Changes in tailwind.config.js fixed warning

/* eslint-env node */

/** @type {import('tailwindcss').Config} */

const colors = require("tailwindcss/colors");

delete colors['lightBlue'];

delete colors['warmGray'];

delete colors['trueGray'];

delete colors['coolGray'];

delete colors['blueGray'];

module.exports = {

content: ["./src/**/*.{vue,js}"],

theme: { extend: { colors }, },

plugins: [],

}