Vue 3 App Template
src/assets/main.css
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--color-background: #ffffff;
--color-background-soft: #f8fafc;
--color-background-mute: #f1f5f9;
--color-border: #e2e8f0;
--color-border-hover: #cbd5e1;
--color-heading: #1e293b;
--color-text: #475569;
--color-text-soft: #64748b;
--color-primary: #0ea5e9;
--color-primary-hover: #0284c7;
--color-primary-soft: #e0f2fe;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: #0f172a;
--color-background-soft: #1e293b;
--color-background-mute: #334155;
--color-border: #475569;
--color-border-hover: #64748b;
--color-heading: #f1f5f9;
--color-text: #cbd5e1;
--color-text-soft: #94a3b8;
--color-primary: #38bdf8;
--color-primary-hover: #0ea5e9;
--color-primary-soft: #0c4a6e;
}
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
src/App.vue
<script setup lang="ts">
import { RouterView } from 'vue-router'
import AppHeader from './components/AppHeader.vue'
</script>
<template>
<div id="app" class="min-h-screen bg-background">
<AppHeader />
<main class="container mx-auto px-4 py-8">
<RouterView />
</main>
</div>
</template>
<style scoped>
#app {
font-weight: normal;
}
</style>
src/components/AppHeader.vue
<script setup lang="ts">
import { ref } from 'vue'
import { RouterLink } from 'vue-router'
const isMenuOpen = ref(false)
const toggleMenu = () => {
isMenuOpen.value = !isMenuOpen.value
}
</script>
<template>
<header class="bg-background-soft border-b border-border">
<nav class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<RouterLink
to="/"
class="text-2xl font-bold text-heading hover:text-primary transition-colors"
>
Vue App
</RouterLink>
<div class="hidden md:flex items-center space-x-6">
<RouterLink
to="/"
class="text-text hover:text-primary transition-colors"
active-class="text-primary font-semibold"
>
Home
</RouterLink>
<RouterLink
to="/about"
class="text-text hover:text-primary transition-colors"
active-class="text-primary font-semibold"
>
About
</RouterLink>
</div>
<button
@click="toggleMenu"
class="md:hidden p-2 rounded-lg hover:bg-background-mute transition-colors"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
<div v-if="isMenuOpen" class="md:hidden mt-4 pb-4 border-t border-border pt-4">
<RouterLink
to="/"
class="block py-2 text-text hover:text-primary transition-colors"
@click="isMenuOpen = false"
>
Home
</RouterLink>
<RouterLink
to="/about"
class="block py-2 text-text hover:text-primary transition-colors"
@click="isMenuOpen = false"
>
About
</RouterLink>
</div>
</nav>
</header>
</template>
src/views/HomeView.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import HelloWorld from '../components/HelloWorld.vue'
const count = ref(0)
const increment = () => {
count.value++
}
onMounted(() => {
console.log('Home view mounted!')
})
</script>
<template>
<div class="max-w-4xl mx-auto text-center">
<HelloWorld />
<div class="mt-12 p-8 bg-background-soft rounded-xl border border-border">
<h2 class="text-2xl font-bold text-heading mb-4">Interactive Counter</h2>
<p class="text-text-soft mb-6">
Click the button to increment the counter and test Vue's reactivity.
</p>
<div class="flex items-center justify-center gap-4 mb-6">
<button
@click="increment"
class="bg-primary hover:bg-primary-hover text-white px-6 py-3 rounded-lg transition-colors font-semibold"
>
Count: {{ count }}
</button>
</div>
<p class="text-sm text-text-soft">
The counter value is: <span class="font-mono text-primary">{{ count }}</span>
</p>
</div>
</div>
</template>
src/views/AboutView.vue
<template>
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold text-heading mb-6 text-center">About This App</h1>
<div class="prose prose-slate dark:prose-invert mx-auto">
<p class="text-lg text-text leading-relaxed mb-6">
This is a modern Vue 3 application built with the Composition API, TypeScript,
and Tailwind CSS. It demonstrates best practices for Vue development in 2025.
</p>
<div class="bg-background-soft rounded-lg p-6 border border-border mb-6">
<h2 class="text-2xl font-semibold text-heading mb-4">Features</h2>
<ul class="list-disc list-inside space-y-2 text-text">
<li>Vue 3 with Composition API</li>
<li>TypeScript for type safety</li>
<li>Vue Router for navigation</li>
<li>Vite for fast development</li>
<li>Tailwind CSS for styling</li>
<li>ESLint & Prettier for code quality</li>
<li>Responsive design</li>
<li>Dark mode support</li>
</ul>
</div>
<div class="bg-primary-soft rounded-lg p-6 border border-primary/20">
<h3 class="text-xl font-semibold text-heading mb-3">Tech Stack</h3>
<div class="grid grid-cols-2 gap-4 text-sm">
<div>
<strong class="text-heading">Frontend:</strong>
<p class="text-text">Vue 3, TypeScript, Tailwind CSS</p>
</div>
<div>
<strong class="text-heading">Build Tool:</strong>
<p class="text-text">Vite with HMR</p>
</div>
<div>
<strong class="text-heading">Router:</strong>
<p class="text-text">Vue Router 4</p>
</div>
<div>
<strong class="text-heading">Linting:</strong>
<p class="text-text">ESLint, Prettier</p>
</div>
</div>
</div>
</div>
</div>
</template>
src/components/HelloWorld.vue
<script setup lang="ts">
interface Props {
msg?: string
}
const props = withDefaults(defineProps<Props>(), {
msg: 'Welcome to Vue 3'
})
</script>
<template>
<div class="text-center mb-12">
<h1 class="text-5xl font-bold text-heading mb-4">
{{ msg }}
</h1>
<p class="text-xl text-text-soft max-w-2xl mx-auto leading-relaxed">
A modern, fast, and scalable web application built with Vue 3,
TypeScript, and Vite. Experience the power of the Composition API
and reactive programming.
</p>
<div class="flex gap-4 justify-center mt-8">
<a
href="https://vuejs.org/"
target="_blank"
class="bg-primary hover:bg-primary-hover text-white px-6 py-3 rounded-lg transition-colors font-semibold"
>
Learn Vue
</a>
<a
href="https://vitejs.dev/"
target="_blank"
class="border border-border hover:border-border-hover px-6 py-3 rounded-lg transition-colors font-semibold text-text hover:text-heading"
>
Powered by Vite
</a>
</div>
</div>
</template>
src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
meta: {
title: 'Home'
}
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
meta: {
title: 'About'
}
}
]
})
// Dynamic page titles
router.beforeEach((to) => {
document.title = to.meta.title
? `${to.meta.title} | Vue App`
: 'Vue App'
})
export default router
src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './assets/main.css'
const app = createApp(App)
app.use(router)
app.mount('#app')
package.json
{
"name": "vue-app",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.10.4",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^22.10.1",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/eslint-config-prettier": "^10.1.0",
"@vue/eslint-config-typescript": "^14.1.3",
"@vue/tsconfig": "^0.7.0",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-plugin-vue": "^9.31.0",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"tailwindcss": "^3.4.17",
"typescript": "~5.7.2",
"vite": "^6.0.3",
"vue-tsc": "^2.2.0"
}
}
tsconfig.json
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}
tsconfig.app.json
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
tsconfig.node.json
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
port: 3000,
open: true
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router']
}
}
}
}
})
tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
'background': 'var(--color-background)',
'background-soft': 'var(--color-background-soft)',
'background-mute': 'var(--color-background-mute)',
'border': 'var(--color-border)',
'border-hover': 'var(--color-border-hover)',
'heading': 'var(--color-heading)',
'text': 'var(--color-text)',
'text-soft': 'var(--color-text-soft)',
'primary': {
DEFAULT: 'var(--color-primary)',
hover: 'var(--color-primary-hover)',
soft: 'var(--color-primary-soft)',
}
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
}
},
},
plugins: [],
}
postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
env.d.ts
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
README.md
# Vue 3 Modern Template
A modern Vue 3 application built with Composition API, TypeScript, Vue Router, and Tailwind CSS.
## Features
- ā” **Vue 3** - Latest version with Composition API
- š **Vite** - Lightning fast build tool with HMR
- š **TypeScript** - Full TypeScript support with strict mode
- š£ļø **Vue Router** - Official router with dynamic imports
- šØ **Tailwind CSS** - Utility-first CSS framework
- š **Dark Mode** - Built-in dark mode support
- š± **Responsive** - Mobile-first responsive design
- šÆ **ESLint & Prettier** - Code linting and formatting
- š§ **Path Aliases** - Clean imports with @ alias
- šļø **Component Structure** - Well-organized component architecture
## Getting Started
Install dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development
Run the development server:
```bash
# npm
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
# bun
bun run dev
```
The application will open at [http://localhost:3000](http://localhost:3000).
## Production
Build for production:
```bash
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
# bun
bun run build
```
Preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
# bun
bun run preview
```
## Development Tools
Type checking:
```bash
npm run type-check
```
Lint and fix code:
```bash
npm run lint
```
Format code:
```bash
npm run format
```
## Project Structure
```
āāā public/ # Static assets
āāā src/
ā āāā assets/ # CSS and other assets
ā āāā components/ # Reusable Vue components
ā āāā router/ # Vue Router configuration
ā āāā views/ # Page components
ā āāā App.vue # Root component
ā āāā main.ts # Application entry point
āāā index.html # HTML template
āāā vite.config.ts # Vite configuration
āāā tailwind.config.js # Tailwind configuration
āāā tsconfig.*.json # TypeScript configurations
```
## Key Technologies
- **Vue 3**: Modern reactive framework with Composition API
- **TypeScript**: Type-safe JavaScript with excellent IDE support
- **Vite**: Next-generation frontend build tool
- **Vue Router**: Official routing solution for Vue.js
- **Tailwind CSS**: Utility-first CSS framework
- **ESLint**: Code linting and error detection
- **Prettier**: Code formatting and style consistency
## Component Features
- **Composition API**: Modern Vue 3 syntax with `<script setup>`
- **TypeScript Props**: Type-safe component props with interfaces
- **Reactive State**: Vue's reactive system with `ref()` and `reactive()`
- **Navigation**: Vue Router with dynamic page titles
- **Responsive Design**: Mobile-first approach with Tailwind
- **Dark Mode**: CSS custom properties with system preference detection
## Learn More
- [Vue 3 Documentation](https://vuejs.org/)
- [Vue Router Documentation](https://router.vuejs.org/)
- [Vite Documentation](https://vitejs.dev/)
- [Tailwind CSS Documentation](https://tailwindcss.com/)
- [TypeScript Documentation](https://www.typescriptlang.org/)
Want to update?
Subscribe to my blog to receive the latest updates from us.
Monthly articles
New articles will be created every month. No spam
All notification in other notify to you, not spam or advertising.