DEV Community

Cover image for My first look at Vuetify
RoryJZauner
RoryJZauner

Posted on

My first look at Vuetify

I enjoy the UI-elements that are created to the specification outlined as part of Google's Material Design. I had used Material UI for React in the past, so when I started using Vue more intensely, I found myself looking for a similar framework. The answer to my quest came in the form of Vuetify.

I will be sharing my experience in getting to know what this framework is all about.

Summary

  • Project Setup
  • App Layout
  • UI-Elements
  • Final Thoughts

Project Setup

As of time of writing, Vuetify only supports Vue 2.x, which is what I will be using for this tutorial.

Let us first create a vue project using the vue-cli:

vue create vuetify-test

I know, not the most original name, but it is a name.

I am setting this project up with Vue 2.x, as the latest stable release of Vuetify currently does not support Vue 3.x yet.

I am using TypeScript for this project, but you can use whatever you like. Alongside TypeScript, I am also going to be using the class-based syntax for my components.

After the installation has completed, we can cd into the vuetify-test directory and with npm run serve to check that everything went according to plan.

Alt Text

After completing the project setup it is time to add Vuetify to our freshly installed project:

vue add vuetify

This will use the vue-cli-vuetify-plugin to get us up-and-running.

I will be using the default setup:

Alt Text

That's it!

Very simple installation using the vue-cli.

Now use npm run serve to check and you should see a big difference:

Alt Text

Our setup is done - we can now have a play around with our code.

App Layout

For the layout I would like to have a side-navigation with links to the different pages.

First, I am going to get rid of all the boilerplate code that comes with installing Vuetify.

Navigation

Using the <v-navigation-drawer app> we can tell vuetify that we would like a navigation bar on the side. The attribute app tells Vuetify that this element is part of our layout.

Here is what my App.vue looks like:

<template>
  <v-app>
    <v-navigation-drawer app>
      <v-divider></v-divider>
    </v-navigation-drawer>
  </v-app>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class App extends Vue {}
</script>
Enter fullscreen mode Exit fullscreen mode

The @Component may look a little unfamiliar. This is the class-based syntax that Vue optionally allows through the vue-property-decorator package.

Now I am going to add an avatar and a few links to justify the existence of our navigation.

<template>
  <v-app>
    <v-navigation-drawer app>
      <v-list>
        <v-list-item class="d-flex justify-center">
          <v-list-item-avatar 
            color="primary" 
            class="white--text"
          >
             UXE
          </v-list-item-avatar>
        </v-list-item>
      </v-list>
      <v-divider></v-divider>
      <v-list>
        <v-list-item link>
          <v-list-item-icon>
            <v-icon>mdi-email-outline</v-icon>
          </v-list-item-icon>
          <v-list-item-title>Messages</v-list-item-title>
        </v-list-item>
        <v-list-item link>
          <v-list-item-icon>
            <v-icon>mdi-file-sync-outline</v-icon>
          </v-list-item-icon>
          <v-list-item-title>Shared Files</v-list-item-title>
        </v-list-item>
        <v-list-item link>
          <v-list-item-icon>
            <v-icon>mdi-account-outline</v-icon>
          </v-list-item-icon>
          <v-list-item-title>Contact List</v-list-item-title>
        </v-list-item>
        <v-list-item link>
          <v-list-item-icon>
            <v-icon>mdi-archive-outline</v-icon>
          </v-list-item-icon>
          <v-list-item-title>
            Archived Messages
          </v-list-item-title>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>
  </v-app>
</template>
Enter fullscreen mode Exit fullscreen mode

I was certainly a little overwhelmed when I first saw all of the v-this and v-that. So let us break this down a bit.

The v-list is the first new component we are using in this. We are using this component to display our avatar at the top and then again further down to display our links underneath each other.

The v-list-item specifies exactly what it says - an item of our list.

On our v-list-item-avatar we use the color-attribute to specify our background colour of avatar and the class of white--text tells with what colour we want our text to be.

Between the avatar at the top and the links we have this <v-divider> which separates them through a horizontal rule.

Each v-list-item here has a link-attribute - giving them that nice ripple effect when clicking on them.

The v-list-item also is made up of an icon and a label. The framework makes use of this huge Material Design Icons Library for icons. You will find an icon for every occasion here.

We end up with something like this:

Alt Text

That is our navigation done. Let us separate this into its own component.

For that we can create a new file in the src directory and name it whatever you like - I am going to go with SideNavigation.vue and add in the markup:

<template>
  <v-navigation-drawer app>
    <v-list>
      <v-list-item class="d-flex justify-center">
        <v-list-item-avatar color="primary" class="white--text"
          >UXE</v-list-item-avatar
        >
      </v-list-item>
    </v-list>
    <v-divider></v-divider>
    <v-list>
      <v-list-item link>
        <v-list-item-icon>
          <v-icon>mdi-email-outline</v-icon>
        </v-list-item-icon>
        <v-list-item-title>Messages</v-list-item-title>
      </v-list-item>
      <v-list-item link>
        <v-list-item-icon>
          <v-icon>mdi-file-sync-outline</v-icon>
        </v-list-item-icon>
        <v-list-item-title>Shared Files</v-list-item-title>
      </v-list-item>
      <v-list-item link>
        <v-list-item-icon>
          <v-icon>mdi-account-outline</v-icon>
        </v-list-item-icon>
        <v-list-item-title>Contact List</v-list-item-title>
      </v-list-item>
      <v-list-item link>
        <v-list-item-icon>
          <v-icon>mdi-archive-outline</v-icon>
        </v-list-item-icon>
        <v-list-item-title>Archived Messages</v-list-item-title>
      </v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class SideNavigation extends Vue {}
</script>
Enter fullscreen mode Exit fullscreen mode

Now we can add this component in our App.vue.

First import the component at the top, then register it:

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import SideNavigation from "@/components/SideNavigation.vue";

@Component({
  components: {
    SideNavigation,
  },
})
export default class App extends Vue {}
</script>
Enter fullscreen mode Exit fullscreen mode

Finally, you can use it within your template:

<template>
  <v-app>
    <side-navigation></side-navigation>
  </v-app>
</template>
Enter fullscreen mode Exit fullscreen mode

This component does seem rather lonely - let's add some more.

UI-Elements

The Vuetify-team have done a great job in documenting the different ways you can use the beautifully crafted components they have made. I definitely encourage you to have a play around with the different components and see what you can come up with.

Basic Material Design Form

I found the way they make forms very helpful and interesting - therefore I am going to use this as my example for UI-Elements.

Here are docs for forms for those of you who are curious.

Let us create a new file for our signup form - SignUpForm.vue.

The template I will be using will look like this:

<template>
  <v-form>
    <v-container>
      <v-row>
        <v-col cols="12" md="6">
          <v-text-field
            v-model="user.firstName"
            :rules="nameRules"
            :counter="10"
            label="First name"
            required
          ></v-text-field>
        </v-col>

        <v-col cols="12" md="6">
          <v-text-field
            v-model="user.lastName"
            :rules="nameRules"
            :counter="10"
            label="Last name"
            required
          ></v-text-field>
        </v-col>

        <v-col cols="10" md="8">
          <v-text-field
            v-model="user.email"
            :rules="emailRules"
            label="E-mail"
            required
          ></v-text-field>
        </v-col>
      </v-row>
      <v-row>
        <v-col cols="12" md="12">
          <v-btn block color="green darken-2" class="white--text"
            >Submit My Data</v-btn
          >
        </v-col>
      </v-row>
    </v-container>
  </v-form>
</template>
Enter fullscreen mode Exit fullscreen mode

Which yields the following form:

Alt Text

The v-form specifies our form container - within that we use the v-container to add padding on either side.

Inside our v-container we have our v-rows and v-cols. These control how our elements are placed in rows and columns.

If you are familiar with Bootstrap then these concepts shouldn't be totally new to you. The Vuetify Docs themselves state that the framework has been heavily influenced by Bootstrap.

The width of the v-cols can be controlled by using the cols and by using md in this case.

The v-model will look familiar to you, if you have used Vue before. This is how Vue allows us to manage our data - so handling user input or the data that gets sent from an API and many more.

Our two input fields for the first and last name have two props - :rules and :counter.

The :rules prop checks if an error has occurred and displays the correct error message:

private nameRules = [
    (value: string) => !!value || "Field ist required",
    (value: string) =>
      value.length <= 10 || "Maxmimum of 10 Characters allowed",
  ];
Enter fullscreen mode Exit fullscreen mode

The :counter prop, well, counts the number of characters and displays this to the user:

Alt Text

The error states will look like this:

Alt Text

We have 14 instead of the allowed 10 characters in the name.

And if we leave the field blank, we also get an error, because in this case, the field is required:

Alt Text

The full validation rules in my script-tag looks like this:

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class SignUpForm extends Vue {
  private user = {
    firstName: "",
    lastName: "",
    email: "",
  };

  private nameRules = [
    (value: string) => !!value || "Field ist required",
    (value: string) =>
      value.length <= 10 || "Maxmimum of 10 Characters allowed",
  ];

  private emailRules = [
    (value: string) => !!value || "Field is required",
    (value: string) => /.+@.+/.test(value) || "E-Mail must be valid",
  ];
}
</script>
Enter fullscreen mode Exit fullscreen mode

We also have validation rules for our E-Mail-Input - it is a regular expressions that checks if an @-symbol is in the string. If not, it again will display the error message.

Final Thoughts

That is it for this article.

This was a small subsection of what Vuetify has to offer, I can wholeheartedly recommend the documentation if you are interested in using Vuetify in your next project.

The documentation is great because they have different options for you to try out. They have done some really awesome work in making the documentation more interactive and interesting.

You can literally build out a version of your button in the browser, then transfer that into your code:

Alt Text

And then copy the button-markup straight into your project.

If you have used Vuetify or any other Material Design Framework before (does not have to be a Vue-related one) then leave a comment telling me what your experience was.

I'd love to hear from you.

Top comments (0)