Vue Template Syntax
Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance's data.
What You'll Learn
- Text interpolation and expressions
- Attribute bindings with v-bind
- Event handling with v-on
- Conditional and list rendering
- Two-way binding with v-model
Text Interpolation
The most basic form of data binding is text interpolation using the "Mustache" syntax:
vue<script setup> import { ref } from "vue" const message = ref("Hello, Vue!") const rawHtml = ref('<span style="color: red">This is red</span>') </script> <template> <!-- Text interpolation --> <p>Message: {{ message }}</p> <!-- Expressions in templates --> <p>Reversed: {{ message.split("").reverse().join("") }}</p> <p>{{ 1 + 1 }}</p> <p>{{ ok ? "YES" : "NO" }}</p> <!-- Raw HTML (use with caution!) --> <p v-html="rawHtml"></p> </template>
Security Warning
Only use v-html on trusted content. Never use it on user-provided content as it can lead to XSS attacks.
Directives
Directives are special attributes with the v- prefix. Vue provides many built-in directives:
v-bind
Dynamically bind attributes
v-on
Listen to DOM events
v-if / v-show
Conditional rendering
v-for
List rendering
Attribute Bindings (v-bind)
vue<script setup> import { ref } from 'vue' const imageUrl = ref('/images/logo.png') const altText = ref('Company Logo') const isDisabled = ref(true) </script> <template> <img v-bind:src="imageUrl" v-bind:alt="altText" /> <button v-bind:disabled="isDisabled">Submit</button> </template>
Event Handling (v-on)
vue<script setup> import { ref } from 'vue' const count = ref(0) const name = ref('') </script> <template> <!-- Inline handler --> <button @click="count++">Add 1</button> <p>Count: {{ count }}</p> <!-- Accessing event object --> <button @click="(e) => console.log(e.target)"> Log Target </button> </template>
Conditional Rendering
v-if vs v-show
Choose based on your use case
v-if
- True conditional rendering
- Element is destroyed/recreated
- Higher toggle cost
- Lazy: initial render skipped if false
- Best for rare toggle scenarios
v-show
- CSS-based toggling (display: none)
- Element always in DOM
- Higher initial render cost
- No lazy rendering
- Best for frequent toggles
vue<script setup> import { ref } from "vue" const isLoggedIn = ref(false) const userRole = ref("admin") const isVisible = ref(true) </script> <template> <!-- v-if / v-else-if / v-else --> <div v-if="isLoggedIn">Welcome back!</div> <div v-else>Please log in</div> <!-- Multiple conditions --> <div v-if="userRole === 'admin'">Admin Panel</div> <div v-else-if="userRole === 'editor'">Editor Panel</div> <div v-else>User Panel</div> <!-- v-if on template (for multiple elements) --> <template v-if="isLoggedIn"> <h1>Title</h1> <p>Content</p> <button>Action</button> </template> <!-- v-show --> <div v-show="isVisible">I toggle with CSS display property</div> </template>
List Rendering (v-for)
vue<script setup> import { ref } from 'vue' interface User { id: number name: string email: string } const users = ref<User[]>([ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' }, { id: 3, name: 'Charlie', email: 'charlie@example.com' } ]) const object = ref({ title: 'Vue Guide', author: 'Evan You', year: 2024 }) </script> <template> <!-- Array with index --> <ul> <li v-for="(user, index) in users" :key="user.id">{{ index + 1 }}. {{ user.name }} ({{ user.email }})</li> </ul> <!-- Object iteration --> <ul> <li v-for="(value, key, index) in object" :key="key">{{ index }}. {{ key }}: {{ value }}</li> </ul> <!-- Range --> <span v-for="n in 10" :key="n">{{ n }}</span> <!-- With v-if (use template wrapper) --> <template v-for="user in users" :key="user.id"> <li v-if="user.isActive"> {{ user.name }} </li> </template> </template>
⚠️ Key Rule
Always use a unique :key attribute when using v-for. This helps Vue track items and optimize updates.
Two-Way Binding (v-model)
vue<script setup> import { ref } from 'vue' const message = ref('') </script> <template> <input v-model="message" placeholder="Type here" /> <p>Message: {{ message }}</p> <!-- v-model is syntactic sugar for: --> <input :value="message" @input="message = $event.target.value" /> </template>
Practice Exercise
Create a Todo List component using what you've learned:
vue<script setup lang="ts"> import { ref, computed } from "vue" interface Todo { id: number text: string completed: boolean } // TODO: Implement the logic const todos = ref<Todo[]>([]) const newTodo = ref("") const filter = ref<"all" | "active" | "completed">("all") // Computed property for filtered todos const filteredTodos = computed(() => { // Your implementation }) // Methods function addTodo() { // Your implementation } function removeTodo(id: number) { // Your implementation } function toggleTodo(id: number) { // Your implementation } </script> <template> <!-- Your template here --> </template>
Next Steps
Continue Learning
Now that you understand Vue's template syntax, let's learn about components and how to build reusable UI pieces!
Next Lesson
Components & Props
Additional Resources