display
property (hides or shows it), but the element always remains in the DOM.message
changes, Vue ensures the UI reflecting {{ message }}
updates instantly without manual DOM manipulation.
v-model
creates two-way data binding between form inputs and Vue data. When the input changes, the Vue data updates, and when the Vue data changes, the input reflects it.
<input v-model="username" /> <p>Hello, {{ username }}</p>
{ path: '/about', component: About }
computed: { fullName() { return this.firstName + ' ' + this.lastName } }
<button @click="increment">Click Me</button>Here, the
increment
method will be called when the button is clicked.
v-model
provides two-way data binding between form inputs and data.ref
provides a direct reference to a DOM element or component, accessible with this.$refs
.
watch: { count(newVal, oldVal) { console.log(`Count changed from ${oldVal} to ${newVal}`); } }
setup()
. Instead of separating by options (data, methods, computed), you group by feature. Example:setup() { const count = ref(0); function increment() { count.value++ } return { count, increment } }
export default { data() { return { count: 0 } }, methods: { increment() { this.count++ } } }
<template> <p>{{ message }}</p> </template> <script> export default { data() { return { message: 'Hello Vue' } } } </script> <style> p { color: blue; } </style>
<slot></slot>It is replaced with the content between component tags.
<slot name="header"></slot> <slot name="footer"></slot>You can pass content with
<template v-slot:header>
in the parent component.
<component>
element with :is
. Example:<component :is="currentView"></component>Here
currentView
can be "Home", "About", etc.
const About = () => import('./About.vue');
export const myMixin = { created() { console.log('Mixin used!') } }
setup()
.
<teleport to="body"> <div>Modal Content</div> </teleport>
<keep-alive>
caches inactive components instead of destroying them. Useful for tabs or forms where you don’t want to lose state. Example:<keep-alive> <component :is="view"></component> </keep-alive>
new Vue({ el: '#app', data: { message: 'Hello Vue!' } });In Vue 3:
import { createApp } from 'vue'; createApp({ data: () => ({ message: 'Hello Vue 3!' }) }).mount('#app');
v-bind
or :
shorthand.<img :src="imageUrl" :alt="description" />
v-for
.<li v-for="item in items" :key="item.id">{{ item.name }}</li>
<div :class="{ active: isActive, error: hasError }"></div>
<div :style="{ color: activeColor, fontSize: size + 'px' }"></div>
<form @submit.prevent="onSubmit">...</form>
<button @click.stop="doSomething">Click</button>
<input type="checkbox" v-model="checked" /> <p>{{ checked }}</p>
<input type="checkbox" v-model="fruits" value="Apple"> <input type="checkbox" v-model="fruits" value="Banana"> <p>{{ fruits }}</p>
<input v-model="username" placeholder="Enter name" /> <p>Welcome, {{ username }}</p>
<template> <button @click="count++">Clicked {{ count }} times</button> </template> <script> export default { data: () => ({ count: 0 }) } </script>
props: ['value'], watch: { value(newVal, oldVal) { console.log('Changed from', oldVal, 'to', newVal); } }
<button @click="$emit('custom-event', 'hello')">Send</button>Parent:
<Child @custom-event="receiveMessage" />
computed: { fullName: { get() { return this.first + ' ' + this.last }, set(value) { [this.first, this.last] = value.split(' ') } } }
<li v-for="(value, key) in object" :key="key">{{ key }}: {{ value }}</li>
<template v-if="type === 'A'"> <p>A content</p> </template> <template v-else-if="type === 'B'"> <p>B content</p> </template> <template v-else> <p>Other</p> </template>
<input v-model.lazy="search" />
mounted() { fetch('https://api.example.com/data') .then(res => res.json()) .then(data => this.items = data) }
import axios from 'axios'; mounted() { axios.get('/api/users').then(res => this.users = res.data); }
import { createApp } from 'vue'; import MyComponent from './MyComponent.vue'; const app = createApp(App); app.component('MyComponent', MyComponent); app.mount('#app');
const AsyncComp = defineAsyncComponent(() => import('./MyComp.vue'));
props: { title: { type: String, required: true }, count: { type: Number, default: 0 } }
props: { age: { type: Number, validator: v => v > 0 } }
<div :class="[isActive ? 'active' : 'inactive']"></div>
<div :class="['box', isError ? 'red' : 'green']"></div>
<div :style="{ backgroundColor: bgColor, fontSize: size + 'px' }"></div>
<template> <div> <input v-model="newTask" @keyup.enter="addTask" /> <ul><li v-for="t in tasks" :key="t">{{ t }}</li></ul> </div> </template> <script> export default { data: () => ({ newTask: '', tasks: [] }), methods: { addTask() { this.tasks.push(this.newTask); this.newTask = '' } } } </script>
<script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ data() { return { count: 0 } } }); </script>
import { mount } from '@vue/test-utils'; import Counter from './Counter.vue'; test('increments on click', () => { const wrapper = mount(Counter); wrapper.find('button').trigger('click'); expect(wrapper.text()).toContain('1'); });
npm run buildDeploy the generated
dist/
folder to a hosting service (Netlify, Vercel, GitHub Pages, etc.).
<Suspense> <template #default> <AsyncComponent /> </template> <template #fallback> Loading... </template> </Suspense>
reactive() - creates a reactive object, suitable for multiple properties. ref() - creates a reactive single value, accessed via .value. Example: const state = reactive({ count: 0 }); const count = ref(0);
provide('theme', 'dark'); inject('theme');
errorCaptured(err, instance, info) { console.log(err, info); return false; // stop propagation }
<component :is="currentComponent"></component> currentComponent = 'HomeComponent';
<template> <h1>Title</h1> <p>Paragraph</p> </template>
app.directive('focus', { mounted(el) { el.focus(); } }); <input v-focus />
this.message = 'Hello'; this.$nextTick(() => { console.log('DOM updated'); });
watch([prop1, prop2], ([newVal1, newVal2], [oldVal1, oldVal2]) => { console.log(newVal1, newVal2); });
app.mixin({ created() { console.log('Mixin called in all components'); } });
const AsyncComp = defineAsyncComponent(() => import('./MyComp.vue'));
export default { install(app, options) { app.config.globalProperties.$myPlugin = () => console.log('Plugin used'); } };
<transition name="fade"> <div v-if="show">Hello</div> </transition> .fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter-from, .fade-leave-to { opacity: 0; }
<input ref="myInput" /> this.$refs.myInput.focus();
import { reactive } from 'vue'; const state = reactive({ count: 0, message: 'Hello' });
import { shallowReactive } from 'vue'; const state = shallowReactive({ nested: { count: 0 } });
import { ref } from 'vue'; const count = ref(0); const message = ref('Hello');
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
<slot>Default content</slot>
defineEmits(['update']); emit('update', value);
const routes = [ { path: '/about', component: () => import('./About.vue') } ];
<MyComponent :title="dynamicTitle" />
import { computed, ref } from 'vue'; const first = ref('John'); const last = ref('Doe'); const fullName = computed(() => first.value + ' ' + last.value);
const AsyncComp = defineAsyncComponent(() => import('./Comp.vue'));
<div :style="{ color: isError ? 'red' : 'green' }">Message</div>
<component :is="currentView"></component>
import { ref, onMounted } from 'vue'; const myInput = ref(null); onMounted(() => { myInput.value.focus(); }); <input ref="myInput" />
import { reactive, ref } from 'vue'; const count = ref(0); const message = ref('Hello'); const state = reactive({ count, message });
errorCaptured(err, vm, info) { console.error(err); return false; // stop propagation }
defineEmits(['update', 'delete']); emit('update', data); emit('delete', id);
<Suspense> <template #default> <AsyncComp /> </template> <template #fallback> Loading... </template> </Suspense>
mounted() { fetch('https://api.example.com/data') .then(res => res.json()) .then(data => this.items = data); }
<template> <div v-if="show"> <div class="modal"> <slot>Modal Content</slot> </div> </div> </template> <script> export default { props: ['show'] } </script>
app.directive('focus', { mounted(el) { el.focus(); } }); <input v-focus />
import mitt from 'mitt'; export const bus = mitt(); bus.on('eventName', payload => console.log(payload)); bus.emit('eventName', { message: 'Hello' });
<table> <tr v-for="row in tableData" :key="row.id"> <td v-for="(value, key) in row" :key="key">{{ value }}</td> </tr> </table>
<button @click="isActive = !isActive">Toggle</button> <p>Status: {{ isActive ? 'On' : 'Off' }}</p> data() { return { isActive: false } }
<div> <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{ tab }}</button> <div v-for="tab in tabs" v-show="currentTab === tab">Content for {{ tab }}</div> </div> data() { return { tabs: ['Tab1','Tab2'], currentTab: 'Tab1' } }
<div> <button @click="showMenu = !showMenu">Menu</button> <ul v-if="showMenu"> <li v-for="item in items" :key="item">{{ item }}</li> </ul> </div> data() { return { showMenu: false, items: ['One','Two','Three'] } }
<form @submit.prevent="submitForm"> <input v-model="email" /> <span v-if="!isValid">Invalid email</span> <button type="submit">Submit</button> </form> data() { return { email: '' } }, computed: { isValid() { return this.email.includes('@') } }, methods: { submitForm() { alert('Form submitted') } }
<div @mouseenter="show=true" @mouseleave="show=false"> Hover me <span v-if="show">Tooltip text</span> </div> data() { return { show: false } }
<template> <input :value="modelValue" @input="$emit('update:modelValue',$event.target.value)" /> </template> props: ['modelValue']
import { reactive } from 'vue'; const state = reactive({ count: 0, message: 'Hello' }); state.count++; state.message = 'Hi';
import { ref, watchEffect } from 'vue'; const count = ref(0); watchEffect(() => { console.log(`Count is: ${count.value}`); }); count.value++;
async mounted() { const res = await fetch('https://api.example.com'); const data = await res.json(); this.items = data; }
<Child :modelValue="parentData" @update:modelValue="parentData = $event" /> data() { return { parentData: '' } }
<Suspense> <template #default><component :is="currentView" /></template> <template #fallback>Loading...</template> </Suspense>
<li v-for="(item, index) in items" :key="index">{{ index }} - {{ item }}</li>
<button @click="handleEvent" @mouseover="handleEvent">Click or Hover</button> methods: { handleEvent() { console.log('Event triggered') } }
import { reactive } from 'vue'; const map = reactive(new Map()); map.set('key', 'value'); console.log(map.get('key'));
<div v-if="loading">Loading...</div> <div v-else>Content Loaded</div> data() { return { loading: true } }, mounted() { setTimeout(() => this.loading = false, 2000) }
<div v-show="isVisible">Visible Content</div> data() { return { isVisible: true } }
data() { return { time: 10 } }, mounted() { const timer = setInterval(() => { if(this.time > 0) this.time--; else clearInterval(timer); }, 1000); } <div>{{ time }} seconds left</div>
<th @click="sortBy('name')">Name</th> <tr v-for="item in sortedItems" :key="item.id"> <td>{{ item.name }}</td> </tr> computed: { sortedItems() { return this.items.sort((a,b) => a.name.localeCompare(b.name)); } }, methods: { sortBy(key) { /* change sort key logic */ } }
<div v-for="(item, index) in items" :key="index"> <h3 @click="active = index">{{ item.title }}</h3> <div v-show="active === index">{{ item.content }}</div> </div> data() { return { active: null, items: [...] } }
<div v-if="step === 1">Step 1 Content</div> <div v-else-if="step === 2">Step 2 Content</div> <button @click="step++">Next</button> data() { return { step: 1 } }
<input v-model="search" placeholder="Search"> <li v-for="item in filteredItems" :key="item">{{ item }}</li> computed: { filteredItems() { return this.items.filter(i => i.includes(this.search)); } }
<li v-for="item in pagedItems" :key="item">{{ item }}</li> <button @click="page--">Prev</button> <button @click="page++">Next</button> computed: { pagedItems() { const start = (this.page-1)*this.pageSize; return this.items.slice(start, start + this.pageSize); } }, data() { return { page: 1, pageSize: 5 } }
<div :style="{ backgroundColor: color }">Colored Div</div> data() { return { color: 'red' } }
<div v-for="n in notifications" :key="n.id">{{ n.message }}</div> methods: { addNotification(msg) { this.notifications.push({ id: Date.now(), message: msg }) } }, data() { return { notifications: [] } }
<div :class="{ sticky: isSticky }">Header</div> data() { return { isSticky: false } }, mounted() { window.addEventListener('scroll', () => { this.isSticky = window.scrollY > 100 }) }
<div :style="{ width: progress + '%', backgroundColor: 'green' }"></div> data() { return { progress: 0 } }, mounted() { setInterval(() => { if(progress<100) this.progress += 1 }, 100) }
<div :class="{ dark: isDark }">Content</div> <button @click="isDark = !isDark">Toggle Dark</button> data() { return { isDark: false } }
<Modal v-if="showModal" @close="showModal = false">Content</Modal> data() { return { showModal: false } }, methods: { openModal() { this.showModal = true } }
<div draggable="true" @dragstart="dragStart(item)">Drag Me</div> methods: { dragStart(item) { this.dragged = item } }, data() { return { dragged: null } }
window.addEventListener('scroll', () => { if(window.innerHeight + window.scrollY >= document.body.offsetHeight) { this.loadMore(); } }); methods: { loadMore() { this.items.push(...newItems) } }
<input v-model.lazy="search"> data() { return { search: '' } }
<button v-for="(tab,index) in tabs" @click="active=index">{{ tab }}</button> <div v-for="(tab,index) in tabs" v-show="active===index">Content {{ tab }}</div> data() { return { tabs:['A','B'], active:0 } }
<div v-cloak>{{ message }}</div> <style> [v-cloak] { display:none; } </style>
<div @mouseenter="show=true" @mouseleave="show=false">Hover Me <span v-if="show">Tooltip</span> </div> data() { return { show:false } }
<transition name="fade"> <div v-if="show">Content</div> </transition> data() { return { show: true } } <style> .fade-enter-active, .fade-leave-active { transition: opacity 0.5s; } .fade-enter, .fade-leave-to { opacity:0; } </style>
<div v-for="(field,index) in fields" :key="index"> <input v-model="field.value" /> </div> data() { return { fields:[{value:''},{value:''}] } }
import { ref, onMounted } from 'vue'; const time = ref(10); onMounted(() => { const timer = setInterval(() => { if(time.value>0) time.value--; else clearInterval(timer); },1000); });
<img v-lazy="imageUrl" alt="Lazy Image"> import VueLazyload from 'vue-lazyload'; app.use(VueLazyload);
app.directive('tooltip', { mounted(el, binding) { el.setAttribute('title', binding.value); } }); <button v-tooltip="'Tooltip text'">Hover Me</button>
router.beforeEach((to, from, next) => { if(to.meta.requiresAuth && !isLoggedIn()) next('/login'); else next(); });
import draggable from 'vuedraggable'; <draggable v-model="list"> <div v-for="item in list" :key="item">{{ item }}</div> </draggable> data() { return { list: ['A','B','C'] } }
<div v-for="(img,index) in images" v-show="current===index"><img :src="img"></div> <button @click="prev">Prev</button> <button @click="next">Next</button> data() { return { images:['a.jpg','b.jpg'], current:0 } }, methods: { prev(){ this.current = (this.current-1+this.images.length)%this.images.length }, next(){ this.current=(this.current+1)%this.images.length } }
<input v-model="email"> <span v-if="!isValidEmail">Invalid Email</span> computed: { isValidEmail(){ return /^[^@]+@[^@]+\.[^@]+$/.test(this.email) } }, data() { return { email:'' } }
data() { return { time: 10000 } }, mounted() { const timer = setInterval(() => { if(this.time>0) this.time-=100; else clearInterval(timer); },100); } <div>{{ (time/1000).toFixed(1) }}s</div>
<svg viewBox="0 0 36 36"> <circle cx="18" cy="18" r="16" stroke-width="4" :stroke-dasharray="progress+',100'" /> </svg> data() { return { progress: 50 } }
import jsPDF from 'jspdf'; methods: { downloadPDF() { const doc = new jsPDF(); doc.text("Hello Vue PDF", 10, 10); doc.save("file.pdf"); } } <button @click="downloadPDF">Download PDF</button>
<header :class="{ sticky: isSticky }">Header</header> data() { return { isSticky:false } }, mounted() { window.addEventListener('scroll', () => this.isSticky = window.scrollY>100) }
<label> <input type="checkbox" v-model="isOn"> <span>Toggle</span> </label> data() { return { isOn:false } }
<span v-for="n in 5" :key="n" @click="rating=n">{{ n <= rating ? '★':'☆' }}</span> data() { return { rating:0 } }
<input type="file" @change="onFileChange"> methods: { onFileChange(e){ this.file = e.target.files[0] } }, data() { return { file:null } }
data() { return { time:3600 } }, computed: { hours() { return Math.floor(this.time/3600) }, minutes() { return Math.floor((this.time%3600)/60) }, seconds() { return this.time%60 } }, mounted() { setInterval(() => { if(this.time>0)this.time-- },1000) }
<div v-if="showToast">Notification</div> methods: { show(){ this.showToast=true; setTimeout(()=>this.showToast=false,3000) } }, data() { return { showToast:false } }
<input v-model="query"> <li v-for="item in filteredItems">{{ item }}</li> computed: { filteredItems() { return this.items.filter(i => i.includes(this.query)) } }, data() { return { items:['apple','banana'], query:'' } }
<input :type="show?'text':'password'" v-model="password"> <button @click="show=!show">Toggle</button> data() { return { password:'', show:false } }
<aside :class="{ open:isOpen }">Sidebar</aside> <button @click="isOpen=!isOpen">Toggle</button> data() { return { isOpen:false } }
<th @click="sort('name')">Name</th> <tr v-for="item in sorted"><td>{{ item.name }}</td></tr> data() { return { items:[{name:'A'},{name:'B'}], sortKey:'', asc:true } }, computed: { sorted() { return this.items.sort((a,b)=>this.asc?(a[this.sortKey]>b[this.sortKey]?1:-1):(a[this.sortKey]
<div v-for="item in items">{{ item }}</div> window.addEventListener('scroll', () => { if(window.innerHeight + window.scrollY > document.body.offsetHeight-10) loadMore() }); methods: { loadMore(){ this.items.push(...moreItems) } }, data() { return { items:[] } }
<div v-if="showModal">Modal Content</div> <button @click="showModal=true">Open</button> <button @click="showModal=false">Close</button> data() { return { showModal:false } }
<div @drop.prevent="onDrop" @dragover.prevent>Drop files here</div> methods: { onDrop(e){ this.files = e.dataTransfer.files } }, data() { return { files:[] } }
<li v-for="(crumb,index) in breadcrumbs">{{ crumb }}</li> data() { return { breadcrumbs:['Home','About','Profile'] } }
<div v-if="step===1">Step 1</div> <div v-else-if="step===2">Step 2</div> <button @click="nextStep">Next</button> data() { return { step:1 } }, methods: { nextStep(){ if(this.step<2)this.step++ } }
<div v-for="img in images"><img :src="img"></div> data() { return { images:['1.jpg','2.jpg','3.jpg'] } }
<button @click="open=!open">Menu</button> <ul v-if="open"><li>Item 1</li><li>Item 2</li></ul> data() { return { open:false } }
<button v-for="(t,index) in tabs" @click="active=index">{{ t }}</button> <div v-for="(t,index) in tabs" v-show="active===index">{{ t }} Content</div> data() { return { tabs:['Tab1','Tab2'], active:0 } }
<div :style="{ width: progress+'%' }">{{ progress }}%</div> data() { return { progress:0 } }, methods: { increase(){ if(this.progress<100)this.progress+=10 } }
<div @click="open=!open">Header</div> <div v-if="open">Content</div> data() { return { open:false } }
<input type="date" v-model="selectedDate"> data() { return { selectedDate:'' } }
<input type="time" v-model="selectedTime"> data() { return { selectedTime:'' } }
<button @click="count--">-</button> <span>{{ count }}</span> <button @click="count++">+</button> data() { return { count:0 } }
<div class="table-responsive"> <table> <tr v-for="item in items"><td>{{ item.name }}</td></tr> </table> </div> data() { return { items:[{name:'A'},{name:'B'}] } }
<select v-model="selected" multiple> <option v-for="opt in options" :value="opt">{{ opt }}</option> </select> data() { return { selected:[], options:['A','B','C'] } }
<span @mouseover="show=true" @mouseleave="show=false">Hover me</span> <div v-if="show">Tooltip Content</div> data() { return { show:false } }
<div v-if="showModal">{{ content }}</div> <button @click="open('Hello')">Open</button> methods: { open(msg){ this.content=msg; this.showModal=true } }, data() { return { showModal:false, content:'' } }
<div :class="{ flipped:isFlipped }" @click="isFlipped=!isFlipped">Front/Back</div> data() { return { isFlipped:false } }
data() { return { time:10 } }, mounted() { let timer=setInterval(()=>{ if(this.time>0)this.time--; else clearInterval(timer) },1000) }
<input v-model="newTag" @keyup.enter="addTag"> <span v-for="tag in tags">{{ tag }}</span> data() { return { newTag:'', tags:[] } }, methods: { addTag(){ this.tags.push(this.newTag); this.newTag='' } }
<div v-for="img in images"><img :src="img"></div> methods: { next(){ this.index = (this.index+1) % this.images.length } }, data() { return { images:['1.jpg','2.jpg'], index:0 } }
<span v-for="n in 5" @click="rating=n">★</span> data() { return { rating:0 } }
<input :type="show?'text':'password'" v-model="password"> <button @click="show=!show">Toggle</button> data() { return { password:'', show:false } }
<div :class="{ collapsed:isCollapsed }">Sidebar</div> <button @click="isCollapsed=!isCollapsed">Toggle</button> data() { return { isCollapsed:false } }
<span @mouseover="show=true" @mouseleave="show=false">Hover</span> <div v-if="show">{{ tooltipText }}</div> data() { return { show:false, tooltipText:'Dynamic Tooltip' } }
<td v-for="cell in row"><input v-model="cell.value"></td> data() { return { table:[[{value:'A'},{value:'B'}]] } }
<input v-model="query"> <li v-for="item in items.filter(i => i.includes(query))">{{ item }}</li> data() { return { query:'', items:['Apple','Banana'] } }
Vue.directive('focus', { inserted(el){ el.focus() } }) <input v-focus>
<component :is="currentComponent"></component> data() { return { currentComponent:'CompA' } }
<textarea v-model="md"></textarea> <div v-html="compiledMarkdown"></div> computed: { compiledMarkdown(){ return marked(this.md) } }, data() { return { md:'' } }
<div v-if="step===1">Step 1</div> <div v-else-if="step===2">Step 2</div> <button @click="step++">Next</button> data() { return { step:1 } }
<button v-tooltip="'Tooltip Text'">Hover</button> import VTooltip from 'v-tooltip'; app.use(VTooltip)
<draggable v-model="items"><div v-for="i in items">{{ i }}</div></draggable> data() { return { items:['A','B','C'] } }
<button @click="showToast">Show</button> <div v-if="toast">Notification</div> methods:{ showToast(){ this.toast=true; setTimeout(()=>this.toast=false,2000) } }, data(){ return { toast:false } }
<button @click="scrollTop">Top</button> methods:{ scrollTop(){ window.scrollTo(0,0) } }
<div>{{ time }}</div> mounted(){ let t=setInterval(()=>{ if(this.time>0)this.time--; else clearInterval(t) },1000) }, data(){ return { time:10 } }
<header :class="{ sticky:isSticky }">Header</header> mounted(){ window.addEventListener('scroll',()=>this.isSticky=window.scrollY>50) }, data(){ return { isSticky:false } }
<div @drop.prevent="upload" @dragover.prevent>Drop file</div> methods:{ upload(e){ this.file=e.dataTransfer.files[0] } }, data(){ return { file:null } }
<button @click="dark=!dark">Toggle</button> <div :class="{ dark:dark }">Content</div> data(){ return { dark:false } }
<button @click="theme=theme==='light'?'dark':'light'">Switch</button> <div :class="theme">Content</div> data(){ return { theme:'light' } }