Skip to main content
Vue.js for Beginners to Advanced
CHAPTER 04 Beginner

Vue Syntax and Templates

Updated: May 18, 2026
5 min read

# CHAPTER 4

Vue Syntax and Templates

1. Chapter Introduction

Vue's template syntax is one of its greatest strengths — it extends plain HTML with reactive capabilities. If you know HTML, you are 60% of the way to knowing Vue templates. This chapter covers all template syntax features with practical examples.

2. Learning Objectives

  • Use {{ }} interpolation for text and expressions.
  • Bind attributes with v-bind (and : shorthand).
  • Handle events with v-on (and @ shorthand).
  • Use template expressions.
  • Build a dynamic profile card.

3. Text Interpolation

vue
123456789101112131415161718192021222324
<script setup>
import { ref } from &#039;vue'
const name = ref(&#039;Alice')
const score = ref(95)
const isAdmin = ref(true)
const html = ref(&#039;<strong>Bold text</strong>')
</script>

<template>
  <!-- Basic interpolation -->
  <h1>{{ name }}</h1>

  <!-- Expressions inside {{ }} -->
  <p>Grade: {{ score >= 90 ? &#039;A+' : score >= 80 ? 'A' : 'B' }}</p>
  <p>Name length: {{ name.length }}</p>
  <p>Uppercase: {{ name.toUpperCase() }}</p>
  <p>Calculation: {{ score * 1.5 }}</p>

  <!-- Raw HTML (use with caution — XSS risk) -->
  <p v-html="html"></p>

  <!-- One-time render (no reactivity) -->
  <p v-once>{{ name }} (will not update)</p>
</template>

4. Attribute Binding (v-bind / :)

vue
1234567891011121314151617181920212223242526272829
<script setup>
import { ref } from &#039;vue'
const imageUrl = ref(&#039;/images/avatar.jpg')
const altText = ref(&#039;User avatar')
const buttonClass = ref(&#039;btn-primary')
const isDisabled = ref(false)
const linkHref = ref(&#039;https://vuejs.org')
const inputType = ref(&#039;password')
const styles = ref({ color: &#039;blue', fontSize: '18px' })
</script>

<template>
  <!-- v-bind:attribute="data" -->
  <img v-bind:src="imageUrl" v-bind:alt="altText" />

  <!-- Shorthand: :attribute="data" (much more common) -->
  <img :src="imageUrl" :alt="altText" />
  <a :href="linkHref" target="_blank">Visit Vue.js</a>
  <button :disabled="isDisabled" :class="buttonClass">Submit</button>
  <input :type="inputType" />

  <!-- Dynamic class binding -->
  <div :class="{ &#039;text-green': score > 90, 'text-red': score < 60 }">Score status</div>
  <div :class="[&#039;base-class', isAdmin ? 'admin-class' : 'user-class']">Role</div>

  <!-- Inline style binding -->
  <p :style="styles">Styled text</p>
  <p :style="{ color: &#039;red', 'font-weight': 'bold' }">Inline style</p>
</template>

5. Event Handling (v-on / @)

vue
1234567891011121314151617181920212223242526272829303132333435363738
<script setup>
import { ref } from &#039;vue'
const count = ref(0)
const message = ref(&#039;')

function greet(event) {
  alert(`Hello! Button text: ${event.target.textContent}`)
}

function handleInput(event) {
  message.value = event.target.value
}
</script>

<template>
  <!-- v-on:event="handler" -->
  <button v-on:click="count++">Count: {{ count }}</button>

  <!-- Shorthand: @event="handler" -->
  <button @click="count++">Increment</button>
  <button @click="count = 0">Reset</button>
  <button @click="greet">Greet with event</button>

  <!-- Passing arguments -->
  <button @click="count += 5">Add 5</button>

  <!-- Inline handler with $event -->
  <button @click="(e) => greet(e)">Arrow handler</button>

  <!-- Input events -->
  <input @input="handleInput" :value="message" />
  <p>You typed: {{ message }}</p>

  <!-- Mouse events -->
  <div @mouseenter="message = &#039;Hovered!'" @mouseleave="message = ''">
    Hover over me
  </div>
</template>

6. Template Expressions — Rules

vue
1234567891011121314
<template>
  <!-- ✅ These work: single expressions -->
  {{ name.toUpperCase() }}
  {{ isAdmin ? &#039;Admin' : 'User' }}
  {{ [1, 2, 3].join(&#039;, ') }}
  {{ { key: &#039;value' }.key }}

  <!-- ❌ These do NOT work: statements -->
  <!-- {{ let x = 5 }} -->      <!-- Assignment — not allowed -->
  <!-- {{ if (x) { ... } }} -->  <!-- if statement — use ternary instead -->
  <!-- {{ count++ }} -->         <!-- Side effects — use in @click handler -->

  <!-- ✅ Multi-expression workaround: use computed properties -->
</template>

7. Mini Project: Dynamic Profile Card

vue
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
<!-- ProfileCard.vue -->
<script setup>
import { ref, computed } from &#039;vue'

const user = ref({
  name: &#039;Alice Johnson',
  role: &#039;Senior Developer',
  avatar: &#039;https://picsum.photos/seed/alice/100/100',
  bio: &#039;Vue.js enthusiast, open source contributor.',
  skills: [&#039;Vue 3', 'TypeScript', 'Pinia', 'GraphQL'],
  followers: 1284,
  following: 348,
  isFollowing: false
})

const followerCount = computed(() =>
  user.value.isFollowing ? user.value.followers + 1 : user.value.followers
)

function toggleFollow() {
  user.value.isFollowing = !user.value.isFollowing
}
</script>

<template>
  <div class="profile-card">
    <div class="card-header" :style="{ background: &#039;linear-gradient(135deg, #667eea, #764ba2)' }">
      <img :src="user.avatar" :alt="user.name + &#039; avatar'" class="avatar" />
    </div>
    <div class="card-body">
      <h2>{{ user.name }}</h2>
      <p class="role">{{ user.role }}</p>
      <p class="bio">{{ user.bio }}</p>

      <div class="skills">
        <span v-for="skill in user.skills" :key="skill" class="skill-badge">
          {{ skill }}
        </span>
      </div>

      <div class="stats">
        <div><strong>{{ followerCount }}</strong><span>Followers</span></div>
        <div><strong>{{ user.following }}</strong><span>Following</span></div>
      </div>

      <button
        @click="toggleFollow"
        :class="[&#039;btn', user.isFollowing ? 'btn-following' : 'btn-follow']"
      >
        {{ user.isFollowing ? &#039;✓ Following' : '+ Follow' }}
      </button>
    </div>
  </div>
</template>

<style scoped>
.profile-card { max-width: 340px; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 32px rgba(0,0,0,.15); font-family: sans-serif; }
.card-header { padding: 2rem; text-align: center; }
.avatar { width: 80px; height: 80px; border-radius: 50%; border: 4px solid white; }
.card-body { padding: 1.5rem; text-align: center; }
h2 { margin: 0; }
.role { color: #6366f1; font-weight: 600; margin: .25rem 0; }
.bio { color: #64748b; font-size: .9rem; }
.skills { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin: 1rem 0; }
.skill-badge { background: #ede9fe; color: #7c3aed; padding: .25rem .75rem; border-radius: 99px; font-size: .8rem; font-weight: 600; }
.stats { display: flex; justify-content: center; gap: 2rem; margin: 1rem 0; }
.stats div { display: flex; flex-direction: column; }
.stats span { color: #94a3b8; font-size: .8rem; }
.btn { width: 100%; padding: .75rem; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: .2s; }
.btn-follow { background: #6366f1; color: white; }
.btn-following { background: #e2e8f0; color: #475569; }
</style>

8. Common Mistakes

  • Using statements in {{ }}: Only expressions are allowed. {{ if (x) }} is invalid — use {{ x ? a : b }}.
  • v-bind vs : confusion: v-bind:href="url" and :href="url" are identical — : is just the shorthand.

9. MCQs

Question 1

Template interpolation syntax?

Question 2

v-bind:src="imgUrl" shorthand?

Question 3

v-on:click="handler" shorthand?

Question 4

What does v-html="rawHtml" do?

Question 5

What does v-once do?

Question 6

Dynamic class binding with condition?

Question 7

Can you use if statements inside {{ }}?

Question 8

What does :disabled="isDisabled" do?

Question 9

Multiple class binding with array?

Question 10

@mouseenter="handler" listens for?

10. Interview Questions

  • Q: What is the difference between v-bind and v-model?
  • Q: Why is v-html potentially dangerous and when is it safe?

11. Summary

Vue templates are supercharged HTML. {{ }} handles text rendering, : binds dynamic attributes, @ handles events. Dynamic class and style binding replace complex DOM manipulation. All template features are reactive — data changes automatically propagate to the DOM.

12. Next Chapter Recommendation

In Chapter 5: Vue Reactivity System, we dive deep into how ref(), reactive(), and Vue's proxy-based reactivity system work under the hood.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·