Build a Twitter Clone With Adonis and Vue

Signing Up Users

For users to be able to sign up for our app, we need to provide a form for them to do that. We'll start by creating a component called SignUpForm. This component will be inside an Auth folder within src/components. So, let's create the Auth folder and the SignUpForm component within it:

mkdir src/components/Auth
touch src/components/Auth/SignUpForm.vue

Now open src/components/Auth/SignUpForm.vue and paste the code below into it:

// src/components/Auth/SignUpForm.vue

  <div class="ui stackable three column centered grid container">
    <div class="column">
      <h2 class="ui dividing header">Sign Up, it's free!</h2>


      <form class="ui form" @submit.prevent="signup">
        <div class="field" :class="{ error: errors.has('name') }">
          <label>Full Name</label>
          <input type="text" name="name" v-model="name" v-validate="'required'" placeholder="Full name">
          <span v-show="errors.has('name')" class="is-danger">{{ errors.first('name') }}</span>

        <div class="field" :class="{ error: errors.has('username') }">
          <input type="text" name="username" :class="{'input': true, 'is-danger': errors.has('username') }" v-model="username" v-validate="'required'" placeholder="Username">
          <span v-show="errors.has('username')" class="is-danger">{{ errors.first('username') }}</span>

        <div class="field" :class="{ error: errors.has('email') }">
          <input type="email" name="email" :class="{'input': true, 'is-danger': errors.has('email') }" v-model="email" v-validate="'required|email'" placeholder="Email">
          <span v-show="errors.has('email')" class="is-danger">{{ errors.first('email') }}</span>

        <div class="field" :class="{ error: errors.has('password') }">
          <input type="password" name="password" :class="{'input': true, 'is-danger': errors.has('password') }" v-model="password" v-validate="'required'" placeholder="Password">
          <span v-show="errors.has('password')" class="is-danger">{{ errors.first('password') }}</span>

        <button class="fluid ui primary button" :disabled="!isFormValid">SIGN UP</button>

        <div class="ui hidden divider"></div>

      <div class="ui divider"></div>

      <div class="ui column grid">
        <div class="center aligned column">
            Got an account? <router-link to="/login">Log In</router-link>

A simple signup form with some fields. We are using the VeeValidate plugin to validate the form input fields. Form input fields errors will be displayed below each field. The signup button is disabled using a computed property isFormValid (which we'll create shortly) until the input fields are properly filled. When the form is submitted a signup (which we'll also create shortly) method will be called.

There is also Notification component that will display any error returned from our API when a user tries to signup.

Next, let's add the corresponding JavaScript to the component. Still within src/components/Auth/SignUpForm.vue, add the code below just after the template section:

// src/components/Auth/SignUpForm.vue

    import Notification from '@/components/Notification';

    export default {
        name: 'SignUpForm',
        components: {
        data() {
            return {
                name: '',
                username: '',
                email: '',
                password: '',
                notification: {
                    message: '',
                    type: '',
        computed: {
            isFormValid() {
                return Object.keys(this.fields).every(key => this.fields[key].valid);
        beforeRouteEnter(to, from, next) {
            const token = localStorage.getItem('tweetr-token');

            return token ? next('/') : next();
        methods: {
            signup() {
                    .post('/signup', {
                        username: this.username,
                        password: this.password,
                    .then(response => {
                        // save token in localstorage

                        // redirect to user home
                    .catch(error => {
                        // display error notification
                        this.notification = Object.assign({}, this.notification, {

First, we import the Notification component used above. Then we define some user data as well as the data for the Notification component. Next, we define the isFormValid computed property that loops and check if each input field is properly filled using the VeeValidate plugin's valid property. Using Vue router's beforeRouteEnter navigation guard, we check if a tweetr-token is available in localStorage which indicates the user is already logged in. If present, we simply redirect to the user homepage, and if not, we show them the signup form.

Finally, we define the signup method which will be called once the form is submitted. Using Axois, we make a POST request to /signup endpoint of our API passing along the data the user entered. If the user was successfully signed up, we save the token returned in localstorage then redirect to the user homepage. If there was an error with the signup process, we display the error returned by passing it to the Notification component.

Adding Signup Route

With the SignUpForm component done, let's add the route which the component will be rendered on. Open src/router/index.js, remove the references to the HelloWorld component, and then add the code below to it:

// src/router/index.js

import SignUpForm from '@/components/Auth/SignUpForm'

// add these inside the `routes` array
    path: '/signup',
    component: SignUpForm

Now when we visit the /signup route, we should see our signup form as in the image below:

Signup form with error:

Like this article? Follow @ammezie on Twitter