Getting Started with Vuetify in Vue 3
If you're here to learn about Vuetify and how to use it with Vue 3, you've come to the right place. In this article, we'll introduce Vuetify, a Material Design component framework for Vue.js, and walk you through setting it up in a Vue 3 project.
We will also build a simple web app that allows us to create and vue jokes. Oh, sorry, view jokes!
What is Vuetify?
Vuetify is a VueJS Material Design component framework. That is to say that Vuetify provides us with prebuilt components and features (e.g. internationalization, tree shaking, theming, etc.) to help us build Vue applications faster. Additionally, Vuetify components have built-in standard functionality, such as validation in form inputs, or various disabled states in buttons.
You can check out a full list of components supported by Vuetify on their official documentation website.
Setting things up
Before we get started, you will need the following on your machine:
- NodeJS installed
- A NodeJS package manager e.g. yarn or npm installed
- Intermediate knowledge of Vue 3.x with the composition API
If you’d like to follow along, feel free to clone the github repository for this article.
`shell
git clone https://github.com/thisdot/blog-demos.git
or `git@github.com:thisdot/blog-demos.git` for ssh
then cd into the project directory
cd getting-started-with-vuetify
`
Installing Vuetify
We will be using yarn` to install and setup Vuetify 3 (the version that supports Vue 3) in this case.
First, let's create a new Vuetify project. You can do this by running the following command in your terminal or command prompt:
`shell
yarn create vuetify
`
This will create a new Vuetify project. For our jokes app, we will use the Essentials (Vuetify, VueRouter, Pinia)` preset when creating our app. We will also be using TypeScript for our app, but this is not necessary.
Since VueJS allows us to build incrementally, if you would like to instead add Vuetify to an existing project, you can use the manual steps provided by the Vuetify team.
Testing our application
Once we have installed and configured our application, cd` into the project's directly, and run the app using the following command:
`shell
yarn dev #or npm run dev` (if using npm instead)
`
Visit localhost:3000/` to see your app in action.
Vuetify project folder structure
Our Vuetify project is generally structured as follows:
- public` - Contains static assets that do not need preprocessing eg. our application `favicon`
- src` - Contains our VueJS source code. We'll mostly be working here.
- assets` - Assets that need to be preprocessed eg. our images that may need to be compressed when building for production
- components`
- layouts` - Layouts
- plugins` - Everything gets wired up here (registration of our app as well as vuetify, our router & pinia)
- router` - Vue router-related functionality
- store` - Pinia store
- styles`
- views` - our web app's "pages"
Worth noting before building
It is worth noting that all components in Vuetify start with a v-` for example:
- v-form` is a form
- v-btn` is a button component
- v-text-field` is an input field
and so on and so forth.
When creating your own components, it is recommended to use a different naming approach so that it is easier to know which components are Vuetify components, and which ones are your components.
Building our Vuetify application
We will build a web app that allows us to add, view and delete jokes.
Here are the steps we will take to build our app:
- Delete unnecessary boilerplate from generated Vuetify app
- Add a joke` pinia store - we'll be using this to store our jokes globally using Pinia
- Create our joke components
- components/jokes/CreateJokeForm.vue` - the form that allows us to add jokes
- components/jokes/JokeList.vue` - Lists our jokes out.
- Add our components to our Home.vue` to view them in our home page
Setting up the jokes pinia store
In the src/store/` directory, create a new file called `joke.ts` that will serve as our Pinia store for storing our jokes. The file content for this will be as follows:
`ts
import { defineStore } from "pinia";
export interface Joke {
id: number;
title: string;
punchline: string;
}
export const useJokeStore = defineStore({
id: "joke",
state: () => ({
jokes: [] as Joke[],
}),
actions: {
addJoke(joke: Joke) {
this.jokes.push(joke);
},
removeJoke(id: number) {
this.jokes = this.jokes.filter((joke) => joke.id !== id);
},
},
});
`
This code defines a special storage space called a "store" for jokes in our Vue.js app. This store keeps track of all the jokes we've added through our app's form. Each joke has an ID, title, and punchline.
The addJoke` function in the store is used to add a new joke to the store when a user submits the form. The `removeJoke` function is used to delete a joke from the store when a user clicks the delete button.
By using this store, we can keep track of all the jokes that have been added through the app, and we can easily add or remove jokes without having to manage the list ourselves.
Creating the joke components
CreateJokeForm.vue
Create a file in src/components/jokes/` called `CreateJokeForm.vue`. This file defines a Vue.js component that displays a form for adding new jokes. The file should have the following contents:
Template section
`html
Submit Joke
`
In the template section, we define a form using the v-form component from Vuetify. We bind the form's submit event to the submitJoke method, which will be called when the form is submitted.
Inside the form, we have two text fields" one for the joke title, and one for the punchline. These text fields are implemented using the v-text-field component from Vuetify. The label prop sets the label for each text field, and the outlined prop creates an outlined style for each text field. The required prop sets the fields as required, meaning that they must be filled in before the form can be submitted.
Finally, we have a submit button implemented using the v-btn component from Vuetify. The button is disabled until both the title and punchline fields are filled in, which is accomplished using the :disabled prop with a computed property that checks if both fields are empty.
Script section
`ts
import { computed, ref } from "vue";
import { Joke, useJokeStore } from "@/store/joke";
const jokeStore = useJokeStore();
const jokeTitle = ref("");
const jokePunchline = ref("");
const joke = computed(() => ({
id: jokeStore.jokes.length + 1,
title: jokeTitle.value,
punchline: jokePunchline.value,
}));
function submitJoke() {
jokeStore.addJoke(joke.value);
jokeTitle.value = "";
jokePunchline.value = "";
}
`
In the script section, we import some functions and types from Vue.js and the joke` store. We then define a `jokeStore` variable that holds the instance of the `useJokeStore` function from the `joke` store.
We also define two ref`s, `jokeTitle`, and `jokePunchline`, which hold the values of the form's title and punchline fields, respectively.
We then define a computed property, joke`, which creates a new `Joke` object using the `jokeTitle` and `jokePunchline` refs, as well as the length of the `jokes` array in the `jokeStore` to set the `id` property.
Finally, we define a submitJoke` function that calls the `addJoke` method from the `jokeStore` to add the new `joke` object to the store. We also reset the `jokeTitle` and `jokePunchline` refs to empty strings.
JokeList.vue
Template section
This one looks bulky. But in essence, all we are doing is displaying a list of jokes when they are found, and a message that lets us know that there are no jokes if we have none that have been added.
`html
My Jokes
{{ joke.title }}
{{ joke.punchline }}
mdi-delete
You have no jokes. Add some!
`
In the template section, we define a v-card` component, which is a container component used to group related content in Vuetify. The card contains a title, which includes an excited emoticon icon from the `mdi-emoticon-excited-outline` icon set from Material Design Icons, displayed using the `v-icon` component.
The jokes are displayed in a v-list`, which is a component used to display lists in Vuetify. Each joke is represented by a `v-list-item` containing a title and subtitle. The `v-row` and `v-col` components from Vuetify are used to divide each list item into two columns: one column for the joke title and punchline, and another column for the delete button.
The delete button is implemented using the v-btn` component from Vuetify. The button is red, and outlined using the `color="error"` and `variant="outlined"` props, respectively. The `@click` event is used to call the `deleteJoke` function when the button is clicked.
If there are no jokes in the jokeStore`, the component displays an `v-alert` component with a message to add some jokes.
Script section
`ts
import { Joke, useJokeStore } from "@/store/joke";
const jokeStore = useJokeStore();
function deleteJoke(joke: Joke) {
jokeStore.removeJoke(joke.id);
}
`
In the script section, we import some functions and types from the joke` store. We then define a `jokeStore` variable that holds the instance of the `useJokeStore` function from the `joke` store.
We also define a deleteJoke` function that takes a `joke` object as an argument and calls the `removeJoke` method from the `jokeStore` to remove the joke from the store.
This component is called JokeList.vue` and displays a list of jokes using Vuetify components like `v-card`, `v-list`, `v-list-item`, `v-row`, `v-col`, and `v-btn`. The component includes a `deleteJoke` function to remove a joke from the `jokeStore` as well.
Wiring it up
To display our form as well as list of jokes, we will go to the src/views/Home.vue` file and change its contents to the following:
`html
import CreateJokeForm from "@/components/jokes/CreateJokeForm.vue";
import JokeList from "@/components/jokes/JokeList.vue";
`
The Home.vue` file defines a Vue.js view that displays the home page of our app. The view contains a `v-container` component, which is a layout component used to provide a responsive grid system for our app.
Inside the v-container`, we have a `v-row` component, which is used to create a horizontal row of content. The `v-row` contains two `v-col` components, each representing a column of content. The `cols` prop specifies that each column should take up 12 columns on small screens (i.e. the entire row width), while on medium screens, each column should take up 6 columns (i.e. half the row width).
The first v-col` contains the `CreateJokeForm` component, which displays a form for adding new jokes. The second `v-col` contains the `JokeList` component, which is used to display a list of jokes that have been added through the form.
In the script` section of the file, we import the `CreateJokeForm` and `JokeList` components, and register them as components for use in the template.
This view provides a simple and responsive layout for our app's home page, with the CreateJokeForm` and `JokeList` components displayed side by side on medium screens and stacked on small screens.
Bonus: Layouts & Theming
Layouts
Even though we had no need to adjust our layouts in our current jokes application, layouts are an important concept in Vuetify. They allow us to pre-define reusable layouts for our applications. These could include having a different layout for when users are logged in, and when they are logged out or layouts for different types of users.
In our application, we used the default Layout (src/layouts/default/Default.vue`) but Vuetify offers us the flexibility to build different layouts for the different domains in our applications. Vuetify also supports nested layouts. You can learn more about layouts in Vuetify in the official Vuetify documentation.
Theming
If you have specific brand needs for your application. Vuetify has a built-in theming system that allows you to customize the look and feel of your application. You can learn more about theming in the official Vuetify theming documentation.
Conclusion
In this article, we introduced Vuetify, and covered how to set it up with Vue 3. We built a VueJS app that allows us to add and manage jokes. We also discussed how to use various Vuetify components to compose our UI, from v-form` for declaring forms to `v-row` for creating a row/column layout, and `v-list` for displaying a list of items among others.
With this knowledge, you can start using Vuetify in your Vue 3 projects and create stunning user interfaces. Also, if you'd like to start your own VueJS project but need help with how to structure it or would like to skip the tedious setup steps of setting up a VueJS project, you can use the Vue 3 Starter.dev kit to skip the boilerplate and start building!
Next steps for learning Vuetify and Vue 3 development
Now that you have an understanding of Vuetify, it's time to dive deeper into its features, and explore more advanced use cases. To continue your learning journey, consider the following resources:
1. Official Vuetify documentation: The Vuetify documentation is an excellent resource for learning about all the features and components Vuetify offers.
2. Vue 3 documentation: To get the most out of Vuetify, it's essential to have a solid understanding of Vue 3. Read the official Vue 3 documentation and practice building Vue applications.
Happy coding, and have fun exploring the world of Vuetify and Vue 3!...