UI Component Framework
Why Vuetify?
There are number of UI frameworks for Vue out there. Check this comparison. Vuetify is often considered one of the best UI component frameworks for Vue.js due to Material design, Rich Component Library and by design Responsive Design.
Add Vuetify to the project
- Install Vuetify Component Framework
npm install vuetify
npm install -D vite-plugin-vuetify
- Add Vuetify Plugin to Vite configuration
/vite.config.ts
to enable Hot Module Reloading for Vuetify components.
// ...
import Vuetify from 'vite-plugin-vuetify'
export default defineConfig({
plugins: [
// ...
Vuetify(),
],
// ...
})
- Create new file
@/plugins/vuetify.ts
with Vuetify configuration.
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
export default createVuetify({})
- Modify
@/main.ts
to use Vuetify
// ...
import vuetify from './plugins/vuetify'
const app = createApp(App)
// ...
app.use(vuetify)
app.mount('#app')
- Create new test page
@/pages/sandbox/index.vue
and openhttp://localhost:5173/sandbox
to see Vuetify UI Components in action.
<template>
<v-card>
<v-card-title>Title</v-card-title>
<v-card-text>Content</v-card-text>
<v-card-actions>
<v-btn color="primary">Primary</v-btn>
<v-btn color="secondary">Secondary</v-btn>
</v-card-actions>
</v-card>
</template>
Blueprints
Blueprints is a collection of pre-defined Material design defaults. Choose the blueprint and add in @/plugins/vuetify.ts
// ...
import { md3 } from 'vuetify/blueprints'
// ...
export default createVuetify({
// ...
blueprint: md3,
})
Themes
Theme allows to create different themes for your application.
- Create light and dark themes.
@/themes/light.ts
export default {
dark: false,
colors: {
primary: '#9155FD',
secondary: '#8A8D93',
'on-secondary': '#fff',
success: '#56CA00',
info: '#16B1FF',
warning: '#FFB400',
error: '#FF4C51',
'on-primary': '#FFFFFF',
'on-success': '#FFFFFF',
'on-warning': '#FFFFFF',
background: '#F4F5FA',
'on-background': '#3A3541',
'on-surface': '#3A3541',
'grey-50': '#FAFAFA',
'grey-100': '#F0F2F8',
'grey-200': '#EEEEEE',
'grey-300': '#E0E0E0',
'grey-400': '#BDBDBD',
'grey-500': '#9E9E9E',
'grey-600': '#757575',
'grey-700': '#616161',
'grey-800': '#424242',
'grey-900': '#212121',
'perfect-scrollbar-thumb': '#DBDADE',
'skin-bordered-background': '#fff',
'skin-bordered-surface': '#fff',
},
variables: {
'code-color': '#d400ff',
'overlay-scrim-background': '#3A3541',
'overlay-scrim-opacity': 0.5,
'hover-opacity': 0.04,
'focus-opacity': 0.1,
'selected-opacity': 0.12,
'activated-opacity': 0.1,
'pressed-opacity': 0.14,
'dragged-opacity': 0.1,
'border-color': '#3A3541',
'table-header-background': '#F9FAFC',
'custom-background': '#F9F8F9',
'shadow-key-umbra-opacity': 'rgba(var(--v-theme-on-surface), 0.08)',
'shadow-key-penumbra-opacity': 'rgba(var(--v-theme-on-surface), 0.12)',
'shadow-key-ambient-opacity': 'rgba(var(--v-theme-on-surface), 0.04)',
},
}
@/themes/dark.ts
export default {
dark: true,
colors: {
primary: '#9155FD',
secondary: '#8A8D93',
'on-secondary': '#fff',
success: '#56CA00',
info: '#16B1FF',
warning: '#FFB400',
error: '#FF4C51',
'on-primary': '#FFFFFF',
'on-success': '#FFFFFF',
'on-warning': '#FFFFFF',
background: '#28243D',
'on-background': '#E7E3FC',
surface: '#111111',
'on-surface': '#E7E3FC',
'grey-50': '#2A2E42',
'grey-100': '#474360',
'grey-200': '#4A5072',
'grey-300': '#5E6692',
'grey-400': '#7983BB',
'grey-500': '#8692D0',
'grey-600': '#AAB3DE',
'grey-700': '#B6BEE3',
'grey-800': '#CFD3EC',
'grey-900': '#E7E9F6',
'perfect-scrollbar-thumb': '#4A5072',
'skin-bordered-background': '#111111',
'skin-bordered-surface': '#111111',
},
variables: {
'code-color': '#d400ff',
'overlay-scrim-background': '#2C2942',
'overlay-scrim-opacity': 0.6,
'hover-opacity': 0.04,
'focus-opacity': 0.1,
'selected-opacity': 0.12,
'activated-opacity': 0.1,
'pressed-opacity': 0.14,
'dragged-opacity': 0.1,
'border-color': '#E7E3FC',
'table-header-background': '#3D3759',
'custom-background': '#373452',
'shadow-key-umbra-opacity': 'rgba(20, 18, 33, 0.08)',
'shadow-key-penumbra-opacity': 'rgba(20, 18, 33, 0.12)',
'shadow-key-ambient-opacity': 'rgba(20, 18, 33, 0.04)',
},
}
- Import and add customized color schemes for light and dark themes in
@/plugins/vuetify.ts
.
// ...
import light from '@/themes/light'
import dark from '@/themes/dark'
// ...
export default createVuetify({
// ...
theme: {
defaultTheme: 'light',
themes: {
light,
dark,
},
},
//...
})
- Add theme toggling to
@\pages\sandbox\index.vue
and check how it works.
<template>
<v-card>
<v-card-title>Title</v-card-title>
<v-card-text>Content</v-card-text>
<v-card-actions>
<v-btn color="primary">Primary</v-btn>
<v-btn color="secondary">Secondary</v-btn>
<v-spacer></v-spacer>
<v-btn @click="toggleTheme">Toggle theme</v-btn>
</v-card-actions>
</v-card>
</template>
<script setup lang="ts">
import { useTheme } from 'vuetify'
const theme = useTheme()
function toggleTheme() {
theme.global.name.value = theme.global.current.value.dark ? 'light' : 'dark'
}
</script>
Global configuration
Global configuration is one of the most powerful features allowing you to set default prop values globally or per component when setting up your application. As an example, to make all card action buttons outlined globally:
- Create file
@/themes/defaults.ts
export default {
VCardActions: {
VBtn: { variant: 'outlined' },
class: 'd-flex flex-wrap',
},
}
- Import defaults in
@/plugins/vuetify.ts
// ...
import defaults from '@/themes/defaults'
// ...
export default createVuetify({
// ...
defaults,
// ...
})
Icons
To keep bundled size low, it is important to include only icons that are used in the project.
- Install icon library
npm install @mdi/js
- Create file of used icons
@/themes/icons.ts
import { mdiHome } from '@mdi/js'
export default { mdiHome }
- Imports icons into
@/plugins/vuetify.ts
// ...
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'
import icons from '@/themes/icons'
// ...
export default createVuetify({
//...
icons: {
defaultSet: 'mdi',
aliases: {
...aliases,
...icons,
},
sets: {
mdi,
},
},
//...
})
- Add icon to
@/pages/sandbox.vue
...
<v-card-title><v-icon icon="$mdiHome" />Title</v-card-title>
...
Cherries
It is always nice to add some small nuance that differentiates your app from others. Here is an example to provide customized background style.
- Create a new composable
@\composables\ui.ts
for enhanced UI features
export function useCardBackground(color?: string) {
return {
background: color ? `linear-gradient(135deg, ${color}DD 0%, ${color}33 100%)` : undefined,
}
}
- Add custom card background to
@/pages/sandbox.vue
<template>
<v-card :style="useCardBackground('#00FF00')">
<!-- ... -->
</v-card>
</template>
<script setup lang="ts">
// ...
import { useCardBackground } from '@/composables/ui'
// ...
</script>
This function will provide possibility to dynamically adjust object backgrounds.
Custom components
Although each page in Vue is typically a UI component, it is crucial to distinguish between pages, modules specific components and generic, universal, reusable components.
Recommendation is to keep number of components low and rely as much as possible on framework. Vuetify offers vast majority of needed ready to use components. However, custom components are justifiable to create really beneficial and reusable super-features of the app where framework does not provide ones.
Check the Advanced UI Components section.