Skip to content

Template Syntax

Vue templates are HTML extended with a small set of special syntax. Most of it is intuitive once you see it, and it compiles away — the browser never sees Vue syntax, only the rendered HTML.

Use {{ }} to render a value as text:

<script setup lang="ts">
const name = 'Alice'
const year = 2024
</script>
<template>
<p>{{ name }}</p>
<p>Year: {{ year }}</p>
</template>

The expression inside {{ }} is evaluated as JavaScript. If name is a ref, Vue auto-unwraps it — write {{ name }}, not {{ name.value }}.

Any single JavaScript expression works inside {{ }}:

<template>
<p>{{ name.toUpperCase() }}</p>
<p>{{ 2 + 2 }}</p>
<p>{{ isAlive ? 'Living' : 'Deceased' }}</p>
<p>{{ person.name || 'Unknown' }}</p>
</template>

The key constraint: expressions only, not statements. {{ if (x) { } }} is invalid. {{ x ? 'yes' : 'no' }} is fine. If you need complex logic, compute it in <script setup> and reference the result.

Static HTML attributes like class="card" work as normal. For dynamic attributes — values that come from your script — use v-bind:

<script setup lang="ts">
const imageUrl = '/avatar.png'
const isActive = true
</script>
<template>
<img v-bind:src="imageUrl" v-bind:alt="name" />
<div v-bind:class="isActive ? 'card active' : 'card'"></div>
</template>

The shorthand for v-bind: is just : — you will see this everywhere:

<img :src="imageUrl" :alt="name" />
<div :class="isActive ? 'card active' : 'card'"></div>

{{ }} always renders content as text, never HTML. If you render '<strong>bold</strong>' with interpolation, you’ll see the literal angle brackets — not bold text. To render raw HTML you use v-html, but avoid it for user-supplied content (XSS risk).

Templates have a few restrictions worth knowing:

  • Each template should have a single root element in practice (though Vue 3 technically allows multiple)
  • You cannot use console.log or other global browser APIs directly in templates — compute the value in <script setup> first
  • Multi-line expressions inside {{ }} are hard to read — prefer computed properties
  1. In PersonCard.vue, add a const name = 'Alice' and a const birthYear = 1982 in the script.
  2. Use {{ name }} and {{ birthYear }} in the template.
  3. Add a const isDeceased = false and use a ternary to display “Living” or “Deceased”.
  4. Add an :title attribute to the card div that shows the person’s name on hover.
  • {{ expression }} renders a JavaScript expression as text; refs are auto-unwrapped.
  • Only expressions work inside {{ }} — no statements like if or for.
  • v-bind:attr="value" dynamically binds an attribute; shorthand is :attr="value".
  • For complex logic, compute the value in <script setup> and reference the result in the template.