Skip to main content
Vue 3 with Vuetify provides a flexible, progressive framework for building modern web applications with Material Design components.

Overview

Vue 3 combines intuitive template syntax with powerful reactivity and a comprehensive Material Design component library.

Pre-installed Packages

  • Vue 3: Progressive JavaScript framework with Composition API
  • Vite: Next-generation frontend tooling with fast HMR
  • Vuetify 3: Material Design component library
  • Tailwind CSS: Utility-first CSS framework
  • TypeScript: Full type safety
  • Material Design Icons: Icon library

Key Features

  • Composition API with <script setup> syntax
  • Reactive data binding
  • Component-based architecture
  • Vue Router for navigation
  • Fast HMR with Vite
  • Material Design components
  • Built-in theming system

Use Cases

Vue 3 is best suited for:

Progressive Web Apps

Applications with gradual adoption and flexible architecture

Material Design UIs

Projects requiring Google’s Material Design system

Dashboard Apps

Admin panels and data visualization dashboards

Flexible SPAs

Single-page applications with component reusability

Vuetify Components

Vuetify provides a comprehensive set of Material Design components that follow Google’s design guidelines.

Available Components

  • Layout: Container, Row, Col, Spacer, Divider
  • Forms: Btn, TextField, Select, Checkbox, Radio, Switch, Slider, Textarea
  • Data: DataTable, List, Card, Chip, Badge, Avatar
  • Navigation: AppBar, NavigationDrawer, Tabs, Breadcrumbs, BottomNavigation
  • Feedback: Alert, Dialog, Snackbar, ProgressCircular, ProgressLinear, Skeleton
  • Overlays: Menu, Tooltip, Overlay

Component Usage

<script setup lang="ts">
const handleClick = () => {
  console.log('Button clicked');
};
</script>

<template>
  <div class="d-flex gap-2">
    <v-btn color="primary">Primary</v-btn>
    <v-btn color="secondary">Secondary</v-btn>
    <v-btn color="error">Error</v-btn>
    <v-btn variant="outlined">Outlined</v-btn>
    <v-btn variant="text">Text</v-btn>
    <v-btn @click="handleClick">Click Me</v-btn>
  </div>
</template>

Critical Rules

Main File: The entry point is src/App.vue. Do not modify src/main.ts.
Pre-installed: Vuetify is already installed. Do not run installation commands for Vuetify or Tailwind CSS.

File Conventions

  • Main component: src/App.vue
  • Entry point: src/main.ts (do not modify)
  • Component files: ComponentName.vue (PascalCase)
  • Composable files: useFeatureName.ts (camelCase with ‘use’ prefix)
  • Components directory: src/components/
  • Composables directory: src/composables/
  • Utils directory: src/utils/
  • Types directory: src/types/

Component Structure

<script setup lang="ts">
import { ref, computed } from 'vue';

interface Props {
  title: string;
  count?: number;
}

const props = defineProps<Props>();
const emit = defineEmits<{
  update: [value: number]
}>();

const localCount = ref(props.count || 0);
const doubled = computed(() => localCount.value * 2);

const increment = () => {
  localCount.value++;
  emit('update', localCount.value);
};
</script>

<template>
  <div>
    <h2>{{ title }}</h2>
    <p>Count: {{ localCount }}</p>
    <p>Doubled: {{ doubled }}</p>
    <v-btn @click="increment">Increment</v-btn>
  </div>
</template>

<style scoped>
/* Component-scoped styles or use Tailwind classes */
</style>

Project Structure

src/
├── App.vue               # Main application component
├── main.ts               # Entry point (do not modify)
├── components/           # Vue components
├── composables/          # Reusable composition functions
├── utils/                # Utility functions
└── types/                # TypeScript type definitions

Composition API

<script setup lang="ts">
import { ref, reactive } from 'vue';

// Primitive values
const count = ref(0);
const name = ref('John');

// Objects
const user = reactive({
  name: 'Jane',
  age: 25,
  email: '[email protected]'
});

const increment = () => {
  count.value++;
};
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Name: {{ name }}</p>
    <p>User: {{ user.name }} ({{ user.age }})</p>
    <v-btn @click="increment">Increment</v-btn>
  </div>
</template>

Vuetify Theming

// src/plugins/vuetify.ts
import { createVuetify } from 'vuetify';

export default createVuetify({
  theme: {
    defaultTheme: 'light',
    themes: {
      light: {
        colors: {
          primary: '#1976D2',
          secondary: '#424242',
          accent: '#82B1FF',
          error: '#FF5252',
          info: '#2196F3',
          success: '#4CAF50',
          warning: '#FB8C00',
        },
      },
      dark: {
        colors: {
          primary: '#2196F3',
          secondary: '#424242',
        },
      },
    },
  },
});

Styling with Tailwind

Combine Vuetify with Tailwind utilities:
<script setup lang="ts">
import { ref } from 'vue';

const title = ref('Gradient Card');
</script>

<template>
  <v-card class="max-w-md mx-auto mt-8">
    <v-card-title class="bg-gradient-to-r from-blue-500 to-purple-600 text-white">
      {{ title }}
    </v-card-title>
    <v-card-text class="p-6">
      <p class="text-gray-700">Custom styled card with Tailwind</p>
    </v-card-text>
  </v-card>
</template>

Best Practices

<!-- Prefer this -->
<script setup lang="ts">
import { ref } from 'vue';
const count = ref(0);
</script>

<!-- Avoid Options API for new code -->
// src/composables/useFetch.ts
import { ref } from 'vue';

export function useFetch(url: string) {
  const data = ref(null);
  const loading = ref(true);
  
  fetch(url)
    .then(r => r.json())
    .then(json => data.value = json)
    .finally(() => loading.value = false);
  
  return { data, loading };
}
<v-text-field v-model="email" label="Email" />
<!-- Instead of :value and @input -->
interface User {
  id: number;
  name: string;
  email: string;
}

const users = ref<User[]>([]);
<Teleport to="body">
  <v-dialog v-model="dialog">
    <!-- Dialog content -->
  </v-dialog>
</Teleport>

Getting Started

Framework Overview

Examples

API Reference

Build docs developers (and LLMs) love