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
pnpm install vuetify
pnpm install -D vite-plugin-vuetify- Add Vuetify Plugin to Vite configuration
/vite.config.tsto enable Hot Module Reloading for Vuetify components.
// ...
import Vuetify from 'vite-plugin-vuetify'
export default defineConfig({
optimizeDeps: {
entries: [
'src/main.ts',
'src/App.vue',
'src/pages/**/*.{vue,md}',
'src/modules/**/pages/**/*.{vue,md}',
],
include: [
'vuetify',
'vuetify/styles',
'vuetify/components',
'vuetify/directives',
'vuetify/iconsets/mdi-svg',
],
},
plugins: [
// ...
Vuetify(),
],
// ...
})- Create new file
@/plugins/vuetify.tswith Vuetify configuration.
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
export default createVuetify({})- Modify
@/main.tsto use Vuetify
// ...
import vuetify from './plugins/vuetify'
const app = createApp(App)
// ...
app.use(vuetify)
app.mount('#app')- Create new test page
@/pages/sandbox/index.vueand openhttp://localhost:5173/sandboxto 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 @click="console.log('Primary!')" color="primary">Primary</v-btn>
<v-btn @click="console.log('Secondary!')" 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/themes.json
source
{
"light": {
"dark": false,
"colors": {
"background": "#fcfcff",
"surface": "#fcfcff",
"primary": "#00629e",
"secondary": "#526070",
"success": "#41a35c",
"warning": "#d98818",
"error": "#ba1a1a",
"info": "#1c8ee6",
"on-background": "#1a1c1e",
"on-surface": "#1a1c1e",
"on-primary": "#ffffff",
"on-secondary": "#ffffff",
"on-success": "#000000",
"on-warning": "#000000",
"on-error": "#ffffff",
"on-info": "#FFFFFF"
},
"variables": {
"border-color": "#1a1c1e",
"border-opacity": 0.12,
"high-emphasis-opacity": 0.87,
"medium-emphasis-opacity": 0.6,
"disabled-opacity": 0.38,
"idle-opacity": 0.04,
"hover-opacity": 0.04,
"focus-opacity": 0.12,
"selected-opacity": 0.08,
"activated-opacity": 0.12,
"pressed-opacity": 0.12,
"dragged-opacity": 0.08,
"theme-kbd": "#212529",
"theme-on-kbd": "#FFFFFF",
"theme-code": "#F5F5F5",
"theme-on-code": "#000000"
}
},
"dark": {
"dark": true,
"colors": {
"background": "#1a1c1e",
"surface": "#1a1c1e",
"primary": "#99cbff",
"secondary": "#bac8da",
"success": "#41a35c",
"warning": "#d98818",
"error": "#ffb4ab",
"info": "#1c8ee6",
"on-background": "#e2e2e5",
"on-surface": "#e2e2e5",
"on-primary": "#003355",
"on-secondary": "#243240",
"on-success": "#000000",
"on-warning": "#000000",
"on-error": "#690005",
"on-info": "#FFFFFF"
},
"variables": {
"border-color": "#e2e2e5",
"border-opacity": 0.12,
"high-emphasis-opacity": 0.87,
"medium-emphasis-opacity": 0.6,
"disabled-opacity": 0.38,
"idle-opacity": 0.04,
"hover-opacity": 0.04,
"focus-opacity": 0.12,
"selected-opacity": 0.08,
"activated-opacity": 0.12,
"pressed-opacity": 0.12,
"dragged-opacity": 0.08,
"theme-kbd": "#2C2C2C",
"theme-on-kbd": "#FFFFFF",
"theme-code": "#1E1E1E",
"theme-on-code": "#FFFFFF"
}
}
}- Import and add customized color schemes for light and dark themes in
@/plugins/vuetify.ts.
// ...
import { light, dark } from '@/themes/themes.json'
// ...
export default createVuetify({
// ...
theme: {
defaultTheme: 'system',
themes: {
light,
dark,
},
},
//...
})- Add theme toggling to
@\pages\sandbox\index.vueand 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 @click="console.log('Primary!')" color="primary">Primary</v-btn>
<v-btn @click="console.log('Secondary!')" color="secondary">Secondary</v-btn>
<v-btn @click="theme.toggle()">Toggle theme</v-btn>
</v-card-actions>
</v-card>
</template>
<script setup lang="ts">
import { useTheme } from 'vuetify'
const theme = useTheme()
</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
As an example - to change globally how card action buttons are aligned:
export const defaults = {
VCardActions: {
VBtn: { variant: 'outlined' },
class: 'd-flex flex-wrap justify-end gap-2',
},
}- 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
pnpm 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/index.vue
...
<v-card-title><v-icon icon="$mdiHome" />Title</v-card-title>
...Custom Styling
Likely not needed at all, but still an option in some rare cases.
- Create
@/themes/index.css
div.markdown-body h1 {
margin-bottom: 24px;
}
div.markdown-body h2 {
margin-top: 8px;
margin-bottom: 16px;
}
div.markdown-body h3 {
margin-top: 8px;
margin-bottom: 12px;
}
div.markdown-body ul {
margin-bottom: 8px;
}
div.markdown-body li {
margin-left: 24px;
}
div.markdown-body p {
margin-bottom: 8px;
}
div.markdown-body hr {
margin-top: 8px;
margin-bottom: 8px;
}- Import in
@/main.ts
import './themes/index.css'
//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.tsfor enhanced UI features
import { computed } from 'vue'
import { useTheme } from 'vuetify'
export function useCardBackground(color: string) {
const theme = useTheme()
return computed(() => {
const dark = theme.current.value.dark
const grFrom = dark ? '33' : '66'
const grTo = dark ? '66' : '33'
return {
background: `linear-gradient(135deg, ${color}${grFrom} 33%, ${color}${grTo} 100%)`
}
})
}- Add custom card background to
@/pages/sandbox.vue
<template>
<v-card :style="cardBackground">
<v-card-title><v-icon icon="$mdiHome" />Title</v-card-title>
<v-card-text>Content</v-card-text>
<v-card-actions>
<v-btn @click="console.log('Primary!')" color="primary">Primary</v-btn>
<v-btn @click="console.log('Secondary!')" color="secondary">Secondary</v-btn>
<v-btn @click="theme.toggle()">Toggle theme</v-btn>
</v-card-actions>
</v-card>
</template>
<script setup lang="ts">
import { useTheme } from 'vuetify'
import { useCardBackground } from '@/composables/ui'
const theme = useTheme()
const cardBackground = useCardBackground('#0000ff')
</script>This function will provide possibility to dynamically adjust object backgrounds.
