2020 / 04 / 09
How to add Vuetify to Vue.js

Material Design for the greater good!

vue.js
vuetify
material design

Basic setup

This guide builds on Quickstart guide for a new Vue.js project.

Install Vuetify

Let’s use the new vue add command to install Vuetify:

vue add vuetify

You’ll see something along the lines of:

📦  Installing vue-cli-plugin-vuetify...
✔  Successfully installed plugin: vue-cli-plugin-vuetify

? Choose a preset:
Configure (advanced)

? Use a pre-made template?
(will replace App.vue and HelloWorld.vue):
Yes

? Use custom theme?
Yes

? Use custom properties (CSS variables)?
Yes

? Select icon font:
Material Design Icons

? Use fonts as a dependency (for Electron or offline)?
No

? Use a-la-carte components?
Yes

? Select locale:
English

🚀  Invoking generator for vue-cli-plugin-vuetify...
📦  Installing additional dependencies...

⚓  Running completion hooks...

✔  Successfully invoked generator for plugin: vue-cli-plugin-vuetify

Typography

The Material Design guidelines for typography, state that Roboto and Noto are the standard typefaces to use.

When you installed Vuetify through vue add vuetify it modified your public/index.html file and added these lines:

<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"
>

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css"
>

Launch your app

Start your project with:

yarn serve

And visit: http://localhost:8080.

Fix the tests

Our HelloWorld.vue component was changed by the Vuetify installer. Let’s fix it:

--- a/src/components/HelloWorld.vue
+++ b/src/components/HelloWorld.vue
@@ -15,6 +15,8 @@
           Welcome to Vuetify
         </h1>
 
+        <p>{{ msg }}</p>
+
         <p class="subheading font-weight-regular">
           For help and collaboration with other Vuetify developers,
           <br>please join our online
@@ -95,6 +97,13 @@
 export default {
   name: 'HelloWorld',
 
+  props: {
+    msg: {
+      required: true,
+      type: String
+    }
+  },
+
   data: () => ({
     ecosystem: [
       {

Next, let’s fix our unit tests:

--- a/tests/unit/example.spec.js
+++ b/tests/unit/example.spec.js
@@ -1,11 +1,17 @@
-import { shallowMount } from '@vue/test-utils'
+import { createLocalVue, shallowMount } from '@vue/test-utils'
+import Vuetify from 'vuetify'
 import HelloWorld from '@/components/HelloWorld.vue'
 
+const localVue = createLocalVue()
+localVue.use(Vuetify)
+
 describe('HelloWorld.vue', () => {
   it('renders props.msg when passed', () => {
     const msg = 'new message'
     const wrapper = shallowMount(HelloWorld, {
-      propsData: { msg }
+      propsData: { msg },
+      localVue,
+      vuetify: new Vuetify()
     })
     expect(wrapper.text()).toMatch(msg)
   })

Lastly, let’s fix our end-to-end tests:

--- a/tests/e2e/specs/test.js
+++ b/tests/e2e/specs/test.js
@@ -3,6 +3,6 @@
 describe('My First Test', () => {
   it('Visits the app root url', () => {
     cy.visit('/')
-    cy.contains('h1', 'Welcome to Your Vue.js App')
+    cy.contains('h1', 'Welcome to Vuetify')
   })
 })

Everything should be OK now. Verify it by running the unit tests:

yarn test:unit

Now run the end-to-end tests:

yarn test:e2e:headless