Build an Angular login form with Tailwind CSS
Today we're going to build a login form with Angular and Tailwind CSS.
Tailwind CSS + Angular = 🥰
We'll be using a reactive Angular form.
And also be doing input validation to verify that the input we receive is valid. When input is invalid we'll display an error to the user.
Let's get started!
1. Install Tailwind CSS
We can start with NPM to download and install the required Tailwind CSS packages.
npm install -D tailwindcss postcss autoprefixer
Then, after our dependencies are installed we'll run the tailwindcss
command to create the tailwind.config.js
file.
npx tailwindcss init
You'll now have a new file in your projects root directory to configure Tailwind CSS.
Since we're using Angular, we'll need to configure our template paths.
Like this.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,ts}",
],
theme: {
extend: {},
},
plugins: [],
}
And last of all, add the @tailwind styles to our styles.scss
file.
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Other styles here */
h1 {
@apply text-3xl font-bold
}
2. Build our login component with Tailwind CSS
We'll start by using the Angular CLI to generate a login
component.
ng g c login
Then we'll open the login.component.ts
file and add our imports, form and submit function.
import { Component } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule],
templateUrl: './login.component.html',
styleUrl: './login.component.scss'
})
export class LoginComponent {
loginForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required]),
});
submit() {
if (this.loginForm.invalid) {
return;
}
const username = this.loginForm.get('username')?.value;
const password = this.loginForm.get('password')?.value;
// Authenticate with an API or Google Firebase Auth
}
}
We've declared our form group and set up the validators.
Now on to our template's HTML code.
<div class="flex flex-col justify-center items-center bg-white">
<div
class="mx-auto flex w-full flex-col justify-center px-5 pt-0 md:h-[unset]">
<div
class="my-auto mb-auto mt-8 flex flex-col md:mt-[70px] w-[350px] max-w-[450px] mx-auto md:max-w-[450px] lg:mt-[130px] lg:max-w-[450px]">
<p class="font-bold text-center">Sign In</p>
<div>
<form class="mb-4" [formGroup]="loginForm" (ngSubmit)="submit()">
<div class="grid gap-2 mt-2">
<div class="grid gap-4">
<input
class="mr-2.5 mb-2 h-full min-h-[44px] w-full rounded-lg border border-zinc-200 bg-white px-4 py-3 text-sm font-medium focus:outline-0 dark:border-zinc-800 dark:bg-transparent dark:text-white"
id="email" placeholder="name@example.com" type="email" autocapitalize="none"
autocomplete="email" autocorrect="off" name="email"
formControlName="email">
@if (loginForm.get('email')?.touched && loginForm.get('email')?.hasError('required')) {
<p class="text-sm ml-2 text-red-500">Email is required</p>
}
<input
id="password" placeholder="Password" type="password"
autocomplete="current-password"
class="mr-2.5 mb-2 h-full min-h-[44px] w-full rounded-lg border border-zinc-200 bg-white px-4 py-3 text-sm font-medium placeholder:text-zinc-400 focus:outline-0 dark:border-zinc-800 dark:bg-transparent dark:text-white dark:placeholder:text-zinc-400"
name="password"
formControlName="password">
@if (loginForm.get('password')?.touched && loginForm.get('password')?.hasError('required')) {
<p class="text-sm ml-2 text-red-500">Password is required</p>
}
</div>
<button class="whitespace-nowrap bg-slate-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 mt-2 flex h-[unset] w-full items-center justify-center rounded-lg px-4 py-4 text-sm font-medium" [disabled]="loginForm.invalid" type="submit">Sign in</button>
</div>
</form>
</div>
</div>
</div>
</div>
You'll notice that we're using the @if syntax to check for form errors and display an error for the email and password validation fields.
And here's the result!
Till next time,
Daniel Kreider