SignUp form with real-time validation using React + Typescript

Hirunika Karunathilaka
8 min readMar 24, 2020

Hi all !!! Today, I’m going to show you how to create a react js app with typescript and create your first form from scratch.

These are really quick steps you need to follow to set up a new react app. I am using my Visual Studio Code to show you the codes. But you can use your favorite editor. No offense 😁 .

If you have worked with react before and if you have installed create-react-app globally via npm install -g create-react-app, it is better you uninstall the package using npm uninstall -g create-react-app to ensure that npx always uses the latest version. The latest npx always need latest npm versions as well. So, it is better to upgrade your npm too with npm install -g npm@latest.

Initiate the react app

  1. First, open the command prompt and go to any folder where you want to create the new app. Then type the below command. My app name is “demo-app”.
npx create-react-app demo-app --typescript

It will take some time to create your app. After completion, open the created folder in the Visual Studio Code (VS Code). Then open its integrated terminal by going to the menu bar (Terminal -> New Terminal) or by ctrl+Shift+~. This will ease your work 😁.

2. Now you have to install the node modules for your app. So, type the below command in the terminal you opened and hit enter.

npm install

3. Let’s see if your simple default app runs fine without errors.

npm start

If the app opens in your browser like above, you are good to go. Good job !!!👌.

Create our first form

We’ll create a signup form for now.

  1. Go to the explorer in your project and create a “components” folder under the “src” folder. Under the components folder, we implement the necessary parts for our app. Then, create a new file under the components folder and name it as “SignUpForm.tsx”. (tsx extension is for typescript).

2. Let’s fill up our empty SignUpForm.tsx file step by step.

Create a class with the name “SignUp” and extend the React.Component class. Then export this class for future use. That means “SignUp” is now a component. Like this,

import React from "react";export class SignUp extends React.Component{}

To see our output, we have to put our component inside the main “App” component which is in the App.tsx file. Delete the default code inside App() function and put this.

import React from 'react';
import './App.css';
import { SignUp } from './components/SignUpForm';
function App() {
return (
<SignUp/>
);
}

export default App;

Now, render a form. You will see lots of errors because the code is incomplete. Just bear up with me. We’ll resolve them one by one. Add the text in bold in inside the SignUp class.

import React from "react";export class SignUp extends React.Component{
render() {
return (
<div className='wrapper'>
<div className='form-wrapper'>
<h2>Sign Up</h2>
<form onSubmit={this.handleSubmit} noValidate >
<div className='fullName'>
<label htmlFor="fullName">Full Name</label>
<input type='text' name='fullName' onChange= {this.handleChange}/>
</div>
<div className='email'>
<label htmlFor="email">Email</label>
<input type='email' name='email' onChange={this.handleChange}/>
</div>
<div className='password'>
<label htmlFor="password">Password</label>
<input type='password' name='password' onChange={this.handleChange}/>
</div>
<div className='submit'>
<button>Register Me</button>
</div>
</form>
</div>
</div>
);
}

}

So, you can see errors underlined at “handleChange” and “handleSubmit” since we haven’t implemented them. To get rid of the errors, we’ll create functions for them and later change them as we need.

import React from "react";export class SignUp extends React.Component{handleChange = (event : any) => {}
handleSubmit = (event : any) => {}
render() {
...
...
}
}

Now refresh your browser and see your ugly form without any style 😂.

Okay, we’ll style this now.

Create a style.css file inside the components folder and fill like below.

p, div {
font-family: Lato;
}

.wrapper {
height: 97vh;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgb(6, 150, 30);
}

.form-wrapper {
display: flex;
flex-direction: column;
width: 280px;
max-width: 80%;
min-width: 100px;
min-height: 400px;
padding: 20px 40px;
border-radius: 6px;
box-shadow: 0px 8px 36px #222;
background-color: #fefefe;
}

.form-wrapper > h2 {
display: flex;
justify-content: center;
font-family: "Segoe UI", "Ubuntu", "Roboto", "Open Sans", "Helvetica Neue", sans-serif;
font-size: 2em;
font-weight: lighter;
margin-top: 0.25em;
color: #222;
}

form {
width: 100%;
display: flex;
flex-wrap: wrap;
}

label {
margin-bottom: 0.5em;
color: #444;
font-weight: lighter;
}

input {
padding: 10px 10px;
border-radius: 5px;
outline: none;
border: 1px solid #d6d1d5;
}

input::placeholder {
font-size: 1.2em;
font-weight: lighter;
color: #bbb;
}

button {
min-width: 100%;
cursor: pointer;
margin-right: 0.25em;
margin-top: 0.5em;
padding: 0.938em;
border: none;
border-radius: 4px;
background-color: rgb(22, 165, 58);
color: #fefefe;
}
button:hover {
background-color: rgb(6, 73, 11);
color: #fefefe;
}

.username,
.email,
.password {
display: flex;
flex-direction: column;
margin-bottom: 15px;
width: 100%;
}

.submit {
width: 100%;
display: flex;
flex-wrap: wrap;
}

And import the style.css file to SignUpForm.tsx.

import './style.cs';

Refresh the browser, and you will see this 😁.

Now. let’s get back to our form. Up to now, it won’t do anything.

Using our “handleChange” method, we can control the user inputs in our username, email and password fields. So, we can store the changes we make to the input fields on change. For that, we’ll also need to have a constructor that stores those properties (props) 😉.

import React from "react";handleChange = (event : any) => {
event.preventDefault();
const { name, value } = event.target;
this.setState({[name]: value});
console.log(this.state) ;
}
handleSubmit = (event : any) => {}export class SignUp extends React.Component{constructor(props: any) {
super(props);
this.state = {
username : null,
email : null,
password : null
}
}
render() {
...
...
}
}

I put a console.log inside handleChange method so you can see on the console (right-click on the site ->inspect ->console)how the username, email and password changes when you type.

Validate the fields real-time

Okay, what if we want to validate our email when we type? 🤔

For that, we have to have another state property that stores its error in each field. Another thing is , now we are changing our code a little bit by adding two interfaces that define the props and states for our signup form. This structure is widely used in complex websites where we have to maintain lots of props.

Add the 2 interfaces as below and modify the React.Component parameters as well.

import React from "react";interface SignUpProps {
name?: any;
value?: any;
}
interface SignUpState {
username : string,
email : string,
password : string,
errors : {
username : string,
email : string,
password : string
}
}

handleSubmit = (event : any) => {}
export class SignUp extends React.Component<SignUpProps, SignUpState>
{
constructor(props: SignUpProps) {
super(props);
const initialState = {
username : '',
email : '',
password : '',
errors : {
username : '',
email : '',
password : ''
}
}
this.state = initialState;
this.handleChange = this.handleChange.bind(this);
}

Alright, now our form component follows some standard ways. Let’s dig into the handleChange method and set the error conditions for each field. To validate the email, we can use a Regex expression. It can be defined as a constant variable. Put the below constant variable above the two interfaces.

const Regex = RegExp(/^\s?[A-Z0–9]+[A-Z0–9._+-]{0,}@[A-Z0–9._+-]+\.[A-Z0–9]{2,4}\s?$/i);

Finally, we have to set the state at the end of the handleChange method. You can console log to see if it the errors are working 😁

handleChange = (event : any) => {
event.preventDefault();
const { name, value } = event.target;
let errors = this.state.errors;
switch (name) {
case 'username':
errors.username = value.length < 5 ? 'Username must be 5 characters long!': '';
break;
case 'email':
errors.email = Regex.test(value)? '': 'Email is not valid!';
break;
case 'password':
errors.password = value.length < 8 ? 'Password must be eight characters long!': '';
break;
default:
break;
}
this.setState(Object.assign(this.state, { errors,[name]: value }));
console.log(this.state.errors);
}

Hurray !!!! 🤣 It worked fine. But, we have to display the error for the user. Follow with me. If we want to display in the user interface, we need to modify the render () part.

render() {
const {errors} = this.state
return (
<div className='wrapper'>
<div className='form-wrapper'>
<h2>Sign Up</h2>
<form onSubmit={this.handleSubmit} noValidate >
<div className='fullName'>
<label htmlFor="fullName">Full Name</label>
<input type='text' name='fullName' onChange= {this.handleChange}/>
{errors.username.length > 0 && <span style={{color: "red"}}>{errors.username}</span>}
</div>
<div className='email'>
<label htmlFor="email">Email</label>
<input type='email' name='email' onChange={this.handleChange}/>
{errors.email.length > 0 && <span style={{color: "red"}}>{errors.email}</span>}</div>
<div className='password'>
<label htmlFor="password">Password</label>
<input type='password' name='password' onChange={this.handleChange}/>
{errors.password.length > 0 && <span style={{color: "red"}}>{errors.password}</span>}
</div>
<div className='submit'>
<button>Register Me</button>
</div>
</form>
</div>
</div>
);
}

All done. Good job 👌. Now real-time validation is completed. Still, we have not coded for what will happen after we hit “Register Me” button.

For now, we’ll say if there are any errors in the state, we cannot submit anything.

handleSubmit = (event : any) => {
event.preventDefault();
let validity = true;
Object.values(this.state.errors).forEach(
(val) => val.length > 0 && (validity = false)
);
if(validity == true){
console.log("Registering can be done");
}else{
console.log("You cannot be registered!!!")
}

}

Good job all 😍😁. Now you have a beautiful signup form that can do real-time validation. For this tutorial, that’s all folks. Hope it would be useful 😁

--

--