27M/month 27M/month license license MIT MIT issues issues 649 open 649 open Stars Stars 50k 50k An approachable, performant and versatile framework for building web user interfaces. Approachable: Builds on top of standard HTML, CSS and JavaScript with intuitive API and world-class documentation. Performant: Truly reactive, compiler-optimized rendering system that rarely requires manual optimization. Versatile: A rich, incrementally adoptable ecosystem that scales between a library and a full-featured framework. The Progressive JavaScript Framework Journée Vue.js - Jaime Arias | 5 of 117
/ Father of two / Founder @voidzerodev / Creator @vuejs & @vite_js. Chinese-only alt: @yuxiyou Singapore voidzero.dev 2010 1 735 Following 285,1 k Followers v0.6 Dec 8, 2013 Evan You releases the first version of Vue.js v1.0 (Evangelion) Oct 26, 2015 First stable version v2.0 (Ghost in the Shell) Sep 30, 2016 Major rewrite v3.0 (One Piece) Sep 30, 2016 Composition API & TypeScript support Vue 2 EOL Dec 31, 2023 End of Support Journée Vue.js - Jaime Arias | 6 of 117
The Progressive JavaScript Framework │ ◇ Project name (target directory): │ vue-project │ ◆ Select features to include in your project: │ (↑/↓ to navigate, space to select, a to toggle all, enter to confirm) │ ◻ TypeScript │ ◻ JSX Support │ ◻ Pinia (state management) │ ◻ Vitest (unit testing) │ ◻ End-to-End Testing │ ◼ ESLint (error prevention) │ ◼ Prettier (code formatting) └ Journée Vue.js - Jaime Arias | 13 of 117
The Progressive JavaScript Framework │ ◇ Project name (target directory): │ vue-project │ ◆ Select features to include in your project: │ (↑/↓ to navigate, space to select, a to toggle all, enter to confirm) │ ◻ TypeScript │ ◻ JSX Support │ ◼ Router (SPA development) │ ◻ Pinia (state management) │ ◻ Vitest (unit testing) │ ◻ End-to-End Testing │ ◼ Prettier (code formatting) └ Journée Vue.js - Jaime Arias | 13 of 117
The Progressive JavaScript Framework │ ◇ Project name (target directory): │ vue-project │ ◆ Select features to include in your project: │ (↑/↓ to navigate, space to select, a to toggle all, enter to confirm) │ ◻ TypeScript │ ◻ JSX Support │ ◼ Router (SPA development) │ ◻ Pinia (state management) │ ◻ Vitest (unit testing) │ ◻ End-to-End Testing │ ◼ ESLint (error prevention) └ Journée Vue.js - Jaime Arias | 13 of 117
Vue.js - The Progressive JavaScript Framework │ ◇ Project name (target directory): │ vue-project │ ◇ Select features to include in your project: │ (↑/↓ to navigate, space to select, a to toggle all, enter to confirm) │ Router (SPA development), ESLint (error prevention), Prettier (code formatting) │ ◆ Install Oxlint for faster linting? (experimental) Journée Vue.js - Jaime Arias | 13 of 117
install npm run format npm run dev ┌ Vue.js - The Progressive JavaScript Framework │ ◇ Project name (target directory): │ test │ ◇ Select features to include in your project: │ (↑/↓ to navigate, space to select, a to toggle all, enter to confirm) │ Router (SPA development), ESLint (error prevention), Prettier (code formatting) │ ◇ Install Oxlint for faster linting? (experimental) │ No Scaffolding project in /Users/himito/vue-project... Journée Vue.js - Jaime Arias | 13 of 117
folders and files: . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── jsconfig.json # Configure JavaScript language features ├── package.json # Lists project dependencies, scripts, metadata, and more ├── public # Static files (favicon, robots.txt, etc.) ├── src # Main source code lives here └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: ├── index.html # The HTML entry point . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── jsconfig.json # Configure JavaScript language features ├── package.json # Lists project dependencies, scripts, metadata, and more ├── public # Static files (favicon, robots.txt, etc.) ├── src # Main source code lives here └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: ├── jsconfig.json # Configure JavaScript language features . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── package.json # Lists project dependencies, scripts, metadata, and more ├── public # Static files (favicon, robots.txt, etc.) ├── src # Main source code lives here └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: ├── package.json # Lists project dependencies, scripts, metadata, and more . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── jsconfig.json # Configure JavaScript language features ├── public # Static files (favicon, robots.txt, etc.) ├── src # Main source code lives here └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: ├── public # Static files (favicon, robots.txt, etc.) . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── jsconfig.json # Configure JavaScript language features ├── package.json # Lists project dependencies, scripts, metadata, and more ├── src # Main source code lives here └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: ├── src # Main source code lives here . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── jsconfig.json # Configure JavaScript language features ├── package.json # Lists project dependencies, scripts, metadata, and more ├── public # Static files (favicon, robots.txt, etc.) └── vite.config.js # Vite’s config file (tool that runs and builds the app) Journée Vue.js - Jaime Arias | 15 of 117
folders and files: └── vite.config.js # Vite’s config file (tool that runs and builds the app) . ├── eslint.config.ts # Configures ESLint for code linting—rules ├── index.html # The HTML entry point ├── jsconfig.json # Configure JavaScript language features ├── package.json # Lists project dependencies, scripts, metadata, and more ├── public # Static files (favicon, robots.txt, etc.) ├── src # Main source code lives here Journée Vue.js - Jaime Arias | 15 of 117
+ the Vue - Official extension Vue - Official Vue vuejs.org | 5,057,023 installs | (111) | Free | Sponsor Language Support for Vue Install Trouble Installing? WebStorm also provides great built-in support for Vue SFCs. Other IDEs that support the Language Service Protocol (LSP) can also leverage Volar’s core functionalities via LSP: vim / Neovim support via coc-volar . Journée Vue.js - Jaime Arias | 16 of 117
right in the editor during development. ESLint Microsoft microsoft.com | 42,333,852 installs | (242) | Free Integrates ESLint JavaScript into VS Code. Install Trouble Installing? Journée Vue.js - Jaime Arias | 18 of 117
SPA is a web app that loads a single HTML page and dynamically updates the content without reloading the whole page. Journée Vue.js - Jaime Arias | 24 of 117
Fast user experience (no full page reloads) Smooth navigation like a desktop app Ideal for modern web apps (e.g. Gmail, Trello) An SPA is a web app that loads a single HTML page and dynamically updates the content without reloading the whole page. Journée Vue.js - Jaime Arias | 24 of 117
Fast user experience (no full page reloads) Smooth navigation like a desktop app Ideal for modern web apps (e.g. Gmail, Trello) Tradeoffs Slower first load (everything loads up front) Requires JavaScript to function properly SEO can be tricky without special setup An SPA is a web app that loads a single HTML page and dynamically updates the content without reloading the whole page. Journée Vue.js - Jaime Arias | 24 of 117
binding is text interpolation using the "Mustache" syntax. The mustache tag will be replaced with the value of the msg property from the corresponding component instance. 1 2 3 4 5 6 7 <template> <span>Message: {{ msg }}</span> </template> <script setup> const msg = "Hello World" </script> Message: Hello World Journée Vue.js - Jaime Arias | 26 of 117
binding is text interpolation using the "Mustache" syntax. The mustache tag will be replaced with the value of the msg property from the corresponding component instance. It will also be updated whenever the msg property changes. 1 2 3 4 5 6 7 <template> <span>Message: {{ msg }}</span> </template> <script setup> const msg = "Hello World" </script> Message: Hello World Journée Vue.js - Jaime Arias | 26 of 117
indicate that they are special attributes provided by Vue In order to output real HTML, the v-html directive is used: Journée Vue.js - Jaime Arias | 27 of 117
indicate that they are special attributes provided by Vue In order to output real HTML, the v-html directive is used: 1 2 3 4 5 6 7 <template> <p><strong>Using text interpolation:</strong> {{ rawHtml }}</p> <p><strong>Using v-html directive:</strong> <span v-html="rawHtml"></span></p> </template> <script setup> const rawHtml = '<span style="color: red">This should be red.</span>' </script> Using text interpolation: <span style="color: red">This should be red.</span> Using v-html directive: This should be red. Journée Vue.js - Jaime Arias | 27 of 117
indicate that they are special attributes provided by Vue In order to output real HTML, the v-html directive is used: 1 2 3 4 5 6 7 <template> <p><strong>Using text interpolation:</strong> {{ rawHtml }}</p> <p><strong>Using v-html directive:</strong> <span v-html="rawHtml"></span></p> </template> <script setup> const rawHtml = '<span style="color: red">This should be red.</span>' </script> Using text interpolation: <span style="color: red">This should be red.</span> Using v-html directive: This should be red. Journée Vue.js - Jaime Arias | 27 of 117
attributes. The v-bind directive is used. Vue will keep the element’s id attribute in sync with the component’s id property <template> <div v-bind:id="id"></div> </template> <script setup> const id="myDiv" </script> 1 2 3 4 5 6 Journée Vue.js - Jaime Arias | 28 of 117
attributes. The v-bind directive is used. Vue will keep the element’s id attribute in sync with the component’s id property <template> <div :id="id"></div> </template> <script setup> const id="myDiv" </script> 1 2 3 4 5 6 Journée Vue.js - Jaime Arias | 28 of 117
attributes. The v-bind directive is used. Vue will keep the element’s id attribute in sync with the component’s id property <template> <!-- vuejs 3.4+: same as v-bind:id="id" --> <div v-bind:id></div> </template> <script setup> const id="myDiv" </script> 1 2 3 4 5 6 7 Journée Vue.js - Jaime Arias | 28 of 117
attributes. The v-bind directive is used. Vue will keep the element’s id attribute in sync with the component’s id property <template> <!-- vuejs 3.4+: same as v-bind:id="id" --> <div :id></div> </template> <script setup> const id="myDiv" </script> 1 2 3 4 5 6 7 Journée Vue.js - Jaime Arias | 28 of 117
attributes. The v-bind directive is used. Vue will keep the element’s id attribute in sync with the component’s id property If the bound value is null or undefined , then the attribute will be removed from the rendered element. <template> <!-- vuejs 3.4+: same as v-bind:id="id" --> <div :id></div> </template> <script setup> const id="myDiv" </script> 1 2 3 4 5 6 7 Journée Vue.js - Jaime Arias | 28 of 117
indicate true / false values by their presence on an element. The disabled attribute will be included if isDisabled has a truthy value or is an empty string. 1 2 3 4 5 6 7 8 9 <template> <button :disabled="isDisabled" class="px-3 py-2 border border-black"> Follow </button> </template> <script setup> const isDisabled=false </script> Follow Journée Vue.js - Jaime Arias | 29 of 117
indicate true / false values by their presence on an element. The disabled attribute will be included if isDisabled has a truthy value or is an empty string. 1 2 3 4 5 6 7 8 9 <template> <button :disabled="isDisabled" class="px-3 py-2 border border-black"> Follow </button> </template> <script setup> const isDisabled=false </script> Follow Journée Vue.js - Jaime Arias | 29 of 117
single expression, i.e., a piece of code that can be evaluated to a value 1 <template> 2 <!-- this is a statement, not an expression: --> 3 {{ var a = 1 }} 4 5 <!-- flow control won't work either, use ternary expressions --> 6 {{ if (ok) { return message } }} 7 </template> Journée Vue.js - Jaime Arias | 32 of 117
prefix Vue provides a number of built-in directives A directive’s job is to reactively apply updates to the DOM when the value of its expression changes 1 2 3 4 5 6 7 <template> <p v-if="seen">Now you see me</p> </template> <script setup> const seen=false </script> Journée Vue.js - Jaime Arias | 33 of 117
dot, which indicate that a directive should be bound in some special way <!-- .prevent modifier tells the v-on directive to call event.preventDefault() --> <form @submit.prevent="onSubmit">...</form> Journée Vue.js - Jaime Arias | 37 of 117
dot, which indicate that a directive should be bound in some special way <!-- .prevent modifier tells the v-on directive to call event.preventDefault() --> <form @submit.prevent="onSubmit">...</form> https://vuejs.org/guide Journée Vue.js - Jaime Arias | 37 of 117
API functions . In SFCs, Composition API is typically used with <script setup> which allow to use Composition API with less boilerplate. <script setup> </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> 1 2 3 4 5 6 Journée Vue.js - Jaime Arias | 41 of 117
API functions . In SFCs, Composition API is typically used with <script setup> which allow to use Composition API with less boilerplate. <script setup> import { ref } from 'vue' // reactive state const count = ref(0) </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> 1 2 3 4 5 6 7 8 9 10 Journée Vue.js - Jaime Arias | 41 of 117
API functions . In SFCs, Composition API is typically used with <script setup> which allow to use Composition API with less boilerplate. <script setup> import { ref } from 'vue' /** hidden code */ // functions that mutate state and trigger updates function increment() { count.value++ } </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Journée Vue.js - Jaime Arias | 41 of 117
API functions . In SFCs, Composition API is typically used with <script setup> which allow to use Composition API with less boilerplate. <script setup> import { ref, computed } from 'vue' /** hidden code */ // computed properties const fullName = computed(() => `${firstName.value} ${lastName.value}`) </script> <template> <button @click="increment">Count is: {{ count }}</button> </template> 1 2 3 4 5 6 7 8 9 10 11 12 Journée Vue.js - Jaime Arias | 41 of 117
hold any value type, including deeply nested objects, arrays, or JavaScript built-in data structures like Map . A ref will make its value deeply reactive . 1 2 3 4 5 6 7 8 9 import { ref } from 'vue' const obj = ref({ nested: { count: 0 }, arr: ['foo'] }) obj.value.nested.count++ console.log(obj.value) Journée Vue.js - Jaime Arias | 44 of 117
ref which wraps the inner value in a special object, reactive() makes an object itself reactive. 1 2 3 4 5 6 import { reactive } from 'vue' const state = reactive({ count: 0 }) state.count++ console.log(state) { "count": 1 } Journée Vue.js - Jaime Arias | 46 of 117
ref which wraps the inner value in a special object, reactive() makes an object itself reactive. reactive() converts the object deeply: nested objects are also wrapped with reactive() when accessed. 1 2 3 4 5 6 import { reactive } from 'vue' const state = reactive({ count: 0 }) state.count++ console.log(state) { "count": 1 } Journée Vue.js - Jaime Arias | 46 of 117
are JavaScript Proxies and behave just like normal objects. 1 2 3 4 5 6 7 8 9 10 11 12 13 import { reactive } from 'vue' const raw = {} const proxy = reactive(raw) // proxy is NOT equal to the original. console.log(proxy === raw) // calling reactive() on the same object returns the same proxy // console.log(reactive(raw) === proxy) // calling reactive() on a proxy returns itself // console.log(reactive(proxy) === proxy) Journée Vue.js - Jaime Arias | 47 of 117
only works for (objects, arrays, etc). It cannot hold primitive types such as string, number or boolean. object types 1 import { reactive } from 'vue' 2 let state = reactive({ count: 0 }) 3 4 // the above reference ({ count: 0 }) is no longer being tracked 5 // (reactivity connection is lost!) 6 state = reactive({ count: 1 }) Journée Vue.js - Jaime Arias | 48 of 117
only works for (objects, arrays, etc). It cannot hold primitive types such as string, number or boolean. Cannot replace entire object: we can’t easily "replace" a reactive object because the reactivity connection to the first reference is lost. object types 1 import { reactive } from 'vue' 2 let state = reactive({ count: 0 }) 3 4 // the above reference ({ count: 0 }) is no longer being tracked 5 // (reactivity connection is lost!) 6 state = reactive({ count: 1 }) Journée Vue.js - Jaime Arias | 48 of 117
destructure a reactive object’s primitive type property, we will lose the reactivity connection 1 2 3 4 5 6 7 8 9 10 11 import { reactive } from 'vue' const state = reactive({ count: 0 }) // count is disconnected from state.count when destructured. let { count } = state // it does not affect original state count++ console.log(state) { "count": 0 } Journée Vue.js - Jaime Arias | 49 of 117
destructure a reactive object’s primitive type property, we will lose the reactivity connection 1 2 3 4 5 6 7 8 9 10 11 12 13 import { reactive } from 'vue' const state = reactive({ count: 0 }) // the function receives a plain number and won't be able to track changes function increment(value){ value++ } increment(state.count) // we have to pass the entire object in to retain reactivity // function incrementObj(obj){ obj.count++ } // incrementObj(state) console.log(state) { "count": 0 } Journée Vue.js - Jaime Arias | 50 of 117
don’t want to repeat ourselves if we need to include a calculation in the template more than once. 1 2 3 4 5 6 7 8 9 10 11 12 <script setup> import { ref } from 'vue' const newItem = ref("") </script> <template> <div class="flex items-center"> <input v-model="newItem" placeholder="Enter your text..." class="flex-grow p-3 border border-gray-300 rounded-md"/> <span class="ml-4 text-sm text-gray-500">{{ newItem.length }}</span> </div> </template> Enter your text... 0 Journée Vue.js - Jaime Arias | 51 of 117
its only responsibility should be computing and returning that value Avoid mutating computed value: a computed return value should be treated as read-only and never be mutated Journée Vue.js - Jaime Arias | 55 of 117
its only responsibility should be computing and returning that value Avoid mutating computed value: a computed return value should be treated as read-only and never be mutated Journée Vue.js - Jaime Arias | 55 of 117
function can be different types of reactive "sources": a ref (including computed refs), a reactive object, a getter function, or an array of multiple sources <script setup> import { ref, watch } from 'vue' const x = ref(0) // a ref watch(x, (newX) => { console.log(`x is ${newX}`) }) </script> 1 2 3 4 5 6 7 8 9 Journée Vue.js - Jaime Arias | 57 of 117
function can be different types of reactive "sources": a ref (including computed refs), a reactive object, a getter function, or an array of multiple sources <script setup> import { ref, watch } from 'vue' const x = ref(0) const y = ref(0) // getter watch( () => x.value + y.value, (sum) => { console.log(`sum of x + y is: ${sum}`) } 1 2 3 4 5 6 7 8 9 10 11 Journée Vue.js - Jaime Arias | 57 of 117
function can be different types of reactive "sources": a ref (including computed refs), a reactive object, a getter function, or an array of multiple sources <script setup> import { ref, watch } from 'vue' const x = ref(0) const y = ref(0) // array of multiple sources watch([x, () => y.value], ([newX, newY]) => { console.log(`x is ${newX} and y is ${newY}`) }) </script> 1 2 3 4 5 6 7 8 9 10 Journée Vue.js - Jaime Arias | 57 of 117
properties of reactive objects. <script setup> import { reactive, watch } from 'vue' const obj = reactive({ count: 0 }) // this won't work because we are passing a number to watch() watch(obj.count, (count) => { console.log(`Count is: ${count}`) }) </script> 1 2 3 4 5 6 7 8 9 Journée Vue.js - Jaime Arias | 58 of 117
the watcher is automatically in deep mode <script setup> import { reactive, watch } from 'vue' const state = reactive({ count: 0 }) watch(state, () => { /* triggers on deep mutation to state */ }) </script> 1 2 3 4 5 6 7 8 Journée Vue.js - Jaime Arias | 59 of 117
won’t be called until the watched source has changed We can force a watcher’s callback to be executed immediately by passing the immediate: true option 1 2 3 4 5 6 7 8 9 10 11 12 <template> <button @click="count++" class="btn-blue">Count + 1</button> </template> <script setup> import { ref, watch } from 'vue' const count = ref(0) watch(count, (newVal, oldVal) => { alert(`Count changed from ${oldVal} to ${newVal}`) }, { immediate: true }) </script> Journée Vue.js - Jaime Arias | 60 of 117
be rendered and remain in the DOM. It only toggles the display CSS property of the element It doesn’t support the <template> element, nor does it work with v- else . 1 2 3 4 5 6 7 8 9 10 <template> <div class="flex justify-between items-center"> <button class="btn-blue" @click="isVisible = !isVisible">Toggle</button> <span v-show="isVisible">Hello! This message is visible.</span> </div> </template> <script setup> import { ref } from 'vue' const isVisible = ref(true) </script> Toggle Hello! This message is visible. Journée Vue.js - Jaime Arias | 69 of 117
because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. Journée Vue.js - Jaime Arias | 70 of 117
because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. v-if is also lazy: if the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time. Journée Vue.js - Jaime Arias | 70 of 117
because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. v-if is also lazy: if the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time. In comparison, v-show is much simpler – the element is always rendered regardless of initial condition, with CSS-based toggling. Journée Vue.js - Jaime Arias | 70 of 117
because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. v-if is also lazy: if the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time. In comparison, v-show is much simpler – the element is always rendered regardless of initial condition, with CSS-based toggling. Generally speaking, v-if has higher toggle costs while v-show has higher initial render costs. Journée Vue.js - Jaime Arias | 70 of 117
because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. v-if is also lazy: if the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time. In comparison, v-show is much simpler – the element is always rendered regardless of initial condition, with CSS-based toggling. Generally speaking, v-if has higher toggle costs while v-show has higher initial render costs. So prefer v-show if you need to toggle something very often, and prefer v-if if the condition is unlikely to change at runtime. Journée Vue.js - Jaime Arias | 70 of 117
to listen to DOM events and run some JavaScript when they’re triggered. Inline handlers: Inline JavaScript to be executed when the event is triggered. 1 2 3 4 5 6 7 8 <template> <button @click="count++" class="btn-blue">Count is: {{ count }}</button> </template> <script setup> import { ref } from 'vue' const count = ref(0) </script> Count is: 0 Journée Vue.js - Jaime Arias | 78 of 117
a method name, we can also call methods in an inline handler. 1 2 3 4 5 6 7 8 9 10 11 <template> <button @click="say('hello')" class="btn-blue">Say Hello</button> </template> <script setup> import { ref } from 'vue' function say (message) { alert(message) } </script> Say Hello Journée Vue.js - Jaime Arias | 81 of 117
the original DOM event in an inline handler: 1. you can pass it into a method using the special $event variable 2. or use an inline arrow function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <template> <!-- using $event special variable --> <button @click="say('hello', $event)" class="btn-blue">$event</button> <!-- using inline arrow function --> <button @click="(event) => say('hello', event)" class="btn-blue ml-2">function</ </template> <script setup> import { ref } from 'vue' function say (message, event) { if (event) { event.preventDefault() } alert(message) } </script> Journée Vue.js - Jaime Arias | 82 of 117
modify the event behaviour without writing extra JavaScript Event modifiers are directive postfixes denoted by a dot . Journée Vue.js - Jaime Arias | 83 of 117
modify the event behaviour without writing extra JavaScript Event modifiers are directive postfixes denoted by a dot . <!-- the click event's propagation will be stopped --> <!-- i.e., event.stopPropagation() --> <a @click.stop="doSomething"></a> Journée Vue.js - Jaime Arias | 83 of 117
modify the event behaviour without writing extra JavaScript Event modifiers are directive postfixes denoted by a dot . <!-- the click event's propagation will be stopped --> <!-- i.e., event.stopPropagation() --> <a @click.stop="doSomething"></a> <!-- the submit event will no longer reload the page --> <!-- i.e, event.preventDefault() --> <form @submit.prevent="submitForm"> <button type="submit">Submit</button> </form> Journée Vue.js - Jaime Arias | 83 of 117
modify the event behaviour without writing extra JavaScript Event modifiers are directive postfixes denoted by a dot . <!-- the click event's propagation will be stopped --> <!-- i.e., event.stopPropagation() --> <a @click.stop="doSomething"></a> <!-- the submit event will no longer reload the page --> <!-- i.e, event.preventDefault() --> <form @submit.prevent="submitForm"> <button type="submit">Submit</button> </form> <!-- Only triggers if clicked directly on the div (not a child) --> <div @click.self="doThat">...</div> Journée Vue.js - Jaime Arias | 83 of 117
modify the event behaviour without writing extra JavaScript Event modifiers are directive postfixes denoted by a dot . <!-- the click event's propagation will be stopped --> <!-- i.e., event.stopPropagation() --> <a @click.stop="doSomething"></a> <!-- the submit event will no longer reload the page --> <!-- i.e, event.preventDefault() --> <form @submit.prevent="submitForm"> <button type="submit">Submit</button> </form> <!-- Only triggers if clicked directly on the div (not a child) --> <div @click.self="doThat">...</div> <!-- the click event will be triggered at most once --> <a @click.once="doThis"></a> Journée Vue.js - Jaime Arias | 83 of 117
modifiers because the relevant code is generated in the same order <a @click.stop.prevent="doThat"></a> Order matters Journée Vue.js - Jaime Arias | 87 of 117
modifiers because the relevant code is generated in the same order Example @click.prevent.self will prevent click’s default action on the element itself and its children <a @click.stop.prevent="doThat"></a> Order matters Journée Vue.js - Jaime Arias | 87 of 117
modifiers because the relevant code is generated in the same order Example @click.prevent.self will prevent click’s default action on the element itself and its children @click.self.prevent will only prevent click’s default action on the element itself. <a @click.stop.prevent="doThat"></a> Order matters Journée Vue.js - Jaime Arias | 87 of 117
.passive modifiers mirror the options of the native addEventListener method <!-- use capture mode when adding the event listener --> <!-- i.e. an event targeting an inner element is handled --> <!-- here before being handled by that element --> <div @click.capture="doThis">...</div> Journée Vue.js - Jaime Arias | 88 of 117
.passive modifiers mirror the options of the native addEventListener method <!-- use capture mode when adding the event listener --> <!-- i.e. an event targeting an inner element is handled --> <!-- here before being handled by that element --> <div @click.capture="doThis">...</div> <!-- the scroll event's default behavior (scrolling) will happen --> <!-- immediately, instead of waiting for `onScroll` to complete --> <!-- in case it contains `event.preventDefault()` --> <div @scroll.passive="onScroll">...</div> Journée Vue.js - Jaime Arias | 88 of 117
.passive modifiers mirror the options of the native addEventListener method The .passive modifier is typically used with touch event listeners for improving performance on mobile devices. <!-- use capture mode when adding the event listener --> <!-- i.e. an event targeting an inner element is handled --> <!-- here before being handled by that element --> <div @click.capture="doThis">...</div> <!-- the scroll event's default behavior (scrolling) will happen --> <!-- immediately, instead of waiting for `onScroll` to complete --> <!-- in case it contains `event.preventDefault()` --> <div @scroll.passive="onScroll">...</div> Journée Vue.js - Jaime Arias | 88 of 117
KeyboardEvent.key can be used as modifiers (kebab-case), e.g., page-down Vue provides aliases for the most commonly used keys: .enter , .tab , .delete , .esc , .space , .up , .down , .left , .right Journée Vue.js - Jaime Arias | 91 of 117
KeyboardEvent.key can be used as modifiers (kebab-case), e.g., page-down Vue provides aliases for the most commonly used keys: .enter , .tab , .delete , .esc , .space , .up , .down , .left , .right When using the modifiers .ctrl , .alt , .shift , .meta , the event listener is triggered only when the corresponding key is pressed. Journée Vue.js - Jaime Arias | 91 of 117
KeyboardEvent.key can be used as modifiers (kebab-case), e.g., page-down Vue provides aliases for the most commonly used keys: .enter , .tab , .delete , .esc , .space , .up , .down , .left , .right When using the modifiers .ctrl , .alt , .shift , .meta , the event listener is triggered only when the corresponding key is pressed. <!-- Alt + Enter --> <input @keyup.alt.enter="clear" /> Journée Vue.js - Jaime Arias | 91 of 117
KeyboardEvent.key can be used as modifiers (kebab-case), e.g., page-down Vue provides aliases for the most commonly used keys: .enter , .tab , .delete , .esc , .space , .up , .down , .left , .right When using the modifiers .ctrl , .alt , .shift , .meta , the event listener is triggered only when the corresponding key is pressed. <!-- Alt + Enter --> <input @keyup.alt.enter="clear" /> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div> Journée Vue.js - Jaime Arias | 91 of 117
the exact combination of system modifiers needed to trigger an event. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <template> <div class="flex gap-3 justify-center"> <!-- this will fire even if Alt or Ctrl is also pressed --> <button @click.shift="onClick" class="btn-blue">Shift</button> <!-- this will only fire when Shift and no other keys are pressed --> <button @click.shift.exact="onClick" class="btn-blue">Shift Exact</button> <!-- this will only fire when no system modifiers are pressed --> <button @click.exact="onClick" class="btn-blue">No Modifiers</button> </div> </template> <script setup> const onClick = () => alert("Hello !") </script> Shift Shift Exact No Modifiers Journée Vue.js - Jaime Arias | 92 of 117
of <input> elements with corresponding variables in JavaScript ? <template> <input type="text" id="firstname" name="firstname"> </template> https://x.com/niggativebts/status/1388948646964703239 Journée Vue.js - Jaime Arias | 94 of 117
which is essentially syntactic sugar for the above. v-model works not only on text inputs, but also on other input types such as checkboxes, radio buttons, and select dropdowns. 1 2 3 4 5 6 7 8 9 10 <template> <div class="flex items-center"> <input v-model="text" class="flex-grow input-full" placeholder="Write here ... <span class="ml-4 text-sm text-gray-500">{{ text.length }}</span> </div> </template> <script setup> import { ref } from 'vue' const text = ref('') </script> Write here ... 0 Journée Vue.js - Jaime Arias | 96 of 117
input ( .trim ) or typecast automatically as a number ( .number ) By default, v-model updates the data on every input event. .lazy modifies this behaviour to update only after the change event 1 2 3 4 5 6 7 8 9 10 <template> <div class="flex flex-col bg-white p-3 shadow-md space-y-2"> <input v-model.lazy="text" type="text" class="input-full" /> <span class="text-sm">Lazy value: <strong>{{ text }}</strong></span> </div> </template> <script setup> import { ref } from 'vue' const text = ref('') </script> Journée Vue.js - Jaime Arias | 99 of 117
an app into independent and reusable pieces. A component encapsulates its own structure, style, and behavior https://medium.com/js-dojo/vue-data-flow-how- it-works-3ff316a7ffcd Journée Vue.js - Jaime Arias | 102 of 117
in defined in a dedicated file using the .vue extension (SFC) It can be also defined as a plain JavaScript object containing Vue- specific options import { ref } from 'vue' export default { setup() { const count = ref(0) return { count } }, template: ` <button @click="count++"> You clicked me {{ count }} times. </button>` } Journée Vue.js - Jaime Arias | 103 of 117
in defined in a dedicated file using the .vue extension (SFC) It can be also defined as a plain JavaScript object containing Vue- specific options import { ref } from 'vue' export default { setup() { const count = ref(0) return { count } }, // Can also target an in-DOM template: template: '#my-template-element' } Journée Vue.js - Jaime Arias | 103 of 117
in defined in a dedicated file using the .vue extension (SFC) It can be also defined as a plain JavaScript object containing Vue- specific options Multiple components can be exported from the same file import { ref } from 'vue' export default { setup() { const count = ref(0) return { count } }, // Can also target an in-DOM template: template: '#my-template-element' } Journée Vue.js - Jaime Arias | 103 of 117
child components via props Click me Enable customization and reuse of components with dynamic values <template> <Button label="Click me" /> </template> Journée Vue.js - Jaime Arias | 105 of 117
child components via props Click me Enable customization and reuse of components with dynamic values Think of them like function parameters, but for components <template> <Button label="Click me" /> </template> Journée Vue.js - Jaime Arias | 105 of 117
child components via props Click me Enable customization and reuse of components with dynamic values Think of them like function parameters, but for components Props flow one-way: from parent to child <template> <Button label="Click me" /> </template> Journée Vue.js - Jaime Arias | 105 of 117
accepted by a component It’s only available inside <script setup> and doesn’t need to be explicitly imported defineProps also returns an object that we can be accessed in JavaScript if needed. 5 defineProps(['label']) 1 <template> 2 <button class="btn-blue">{{ label }}</button> 3 </template> 4 <script setup> 6 </script> <script setup> const props = defineProps(['title']) console.log(props.title) </script> Journée Vue.js - Jaime Arias | 106 of 117
object syntax The key is the name of the prop, while the value should be the constructor function of the expected type. 1 <script setup> 2 defineProps({ 3 id: Number, 4 title: String, 5 }) 6 </script> 1 <BlogPost v-bind="post" /> 2 <BlogPost :id="post.id" :title="post.title" /> Journée Vue.js - Jaime Arias | 107 of 117
object syntax The key is the name of the prop, while the value should be the constructor function of the expected type. You can use v-bind without an argument to pass all the properties of an object as props 1 <script setup> 2 defineProps({ 3 id: Number, 4 title: String, 5 }) 6 </script> 1 <BlogPost v-bind="post" /> 2 <BlogPost :id="post.id" :title="post.title" /> Journée Vue.js - Jaime Arias | 107 of 117
object syntax The key is the name of the prop, while the value should be the constructor function of the expected type. You can use v-bind without an argument to pass all the properties of an object as props 1 <script setup> 2 defineProps({ 3 id: Number, 4 title: String, 5 }) 6 </script> 2 <BlogPost :id="post.id" :title="post.title" /> 1 <BlogPost v-bind="post" /> Journée Vue.js - Jaime Arias | 107 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // `null` and `undefined` values will allow any type propA: null, propB: undefined, }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Basic type check propC: Number, }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Multiple possible types propD: [String, Number], }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Required string propE: { type: String, required: true }, }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Required but nullable string propF: { type: [String, null], required: true }, }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Number with a default value propG: { type: Number, default: 100 }, }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Function with a default value propH: { type: Function, default() { return 'Default function' } }) <script> Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Object with a default value propI: { type: Object, // Object or array defaults must be returned from a function. default(rawProps) { return { message: 'hello' } } }, Journée Vue.js - Jaime Arias | 108 of 117
props. If a requirement is not met, Vue will warn you in the browser’s JavaScript console The type can be a custom class or one of the following native constructors: String , Number , Boolean , Array , Object , Date , Function , Symbol , Error <script setup> defineProps({ // Custom validator function // full props passed as 2nd argument in 3.4+ propJ: { validator(value, props) { return ['success', 'warning', 'danger'].includes(value) } }, Journée Vue.js - Jaime Arias | 108 of 117
listen to any event on the child component instance with v-on The child component can emit an event on itself by calling the built-in $emit method, passing the name of the event. https://medium.com/js-dojo/vue-data-flow-how- it-works-3ff316a7ffcd Journée Vue.js - Jaime Arias | 109 of 117
listen to any event on the child component instance with v-on The child component can emit an event on itself by calling the built-in $emit method, passing the name of the event. https://medium.com/js-dojo/vue-data-flow-how- it-works-3ff316a7ffcd <template> <Button @btn-clicked="counter++" /> </template> <script setup> import { ref } from 'vue' const counter = ref(0) </script> Journée Vue.js - Jaime Arias | 109 of 117
listen to any event on the child component instance with v-on The child component can emit an event on itself by calling the built-in $emit method, passing the name of the event. https://medium.com/js-dojo/vue-data-flow-how- it-works-3ff316a7ffcd <template> <Button @btn-clicked="counter++" /> </template> <script setup> import { ref } from 'vue' const counter = ref(0) </script> <template> <button @click="$emit('btn-clicked')"> Click </button> </template> Journée Vue.js - Jaime Arias | 109 of 117
used to declare emitted events The defineEmits macro cannot be used inside a function, it must be placed directly within <script setup> It returns an emit function that is equivalent to the $emit method The first argument to emit() is the event name. Any additional arguments are passed on to the event listener. <template> <button class="btn-blue" @click="handleBtn">Click</button> </template> <script setup> const emit = defineEmits(['btn-clicked']) const handleBtn = () => emit('btn-clicked', 1, 'hello') </script> Journée Vue.js - Jaime Arias | 110 of 117
validated if it is defined with the object syntax instead of the array syntax To add validation, the event is assigned a function that receives the arguments passed to the emit call and returns a boolean. <script setup> const emit = defineEmits({ click: null, // No validation }) </script> Journée Vue.js - Jaime Arias | 111 of 117
validated if it is defined with the object syntax instead of the array syntax To add validation, the event is assigned a function that receives the arguments passed to the emit call and returns a boolean. <script setup> const emit = defineEmits(['submit']) function submitForm(email, password) { emit('submit', { email, password }) } </script> Journée Vue.js - Jaime Arias | 111 of 117
validated if it is defined with the object syntax instead of the array syntax To add validation, the event is assigned a function that receives the arguments passed to the emit call and returns a boolean. <script setup> const emit = defineEmits({ // Validate submit event submit: ({ email, password }) => email && password }) function submitForm(email, password) { emit('submit', { email, password }) } </script> Journée Vue.js - Jaime Arias | 111 of 117
List tasks Delete a task Toggle task completion Filter tasks (all/todo/done) Suggested Component Structure TaskList.vue – Displays the list of tasks AddTaskForm.vue – Input form to add new tasks FilterButton.vue – Filter buttons Card.vue – Reusable component using <slot> Build a Task Manager App using Vue.js 3, designed to help users manage their daily tasks. Journée Vue.js - Jaime Arias | 115 of 117