Template Syntax
|
This section documents the current Vue 3.x release line as published at
the official Vue.js documentation, which is the reference these pages are written and
verified against. No specific patch version is pinned. The Composition API with This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since Vue and its ecosystem iterate quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
Vue templates are valid HTML extended with interpolations and directives. The compiler turns a template
into a render function; at runtime Vue keeps the DOM in sync with the component’s reactive state. This page
follows Template Syntax and the
built-in directives reference, then covers binding class
and style.
Text interpolation
The double-brace mustache syntax inserts a value as plain text. It reacts to changes and is always escaped, so the content is never parsed as HTML.
<template>
<span>Message: {{ msg }}</span>
<span>{{ ok ? 'YES' : 'NO' }}</span>
</template>
To skip compilation of a block entirely, use v-pre; to show the raw markup until the component is ready,
v-cloak paired with a CSS rule. Both are in the directives reference.
Raw HTML with v-html
\{\{ }} cannot output real HTML. v-html sets an element’s innerHTML from a string:
<template>
<div v-html="renderedMarkdown"></div>
</template>
v-html runs whatever markup you give it. Never pass user-supplied or otherwise untrusted content
through it — that is a cross-site scripting hole. Sanitize on the server or with a vetted library first, and
see Security and Accessibility for the full rules.
|
Attribute bindings with v-bind
Mustaches do not work inside attributes. Bind an attribute to an expression with v-bind:, almost always
written with its : shorthand:
<template>
<img :src="imageUrl" :alt="imageAlt">
<a :href="`/users/${user.id}`">Profile</a>
</template>
Boolean attributes. When the bound value is null, undefined or false, Vue removes the attribute
entirely; any other value adds it:
<template>
<button :disabled="isSubmitting">Save</button>
</template>
Same-name shorthand. If the attribute and the bound variable share a name, Vue 3.4+ lets you write just
:id instead of :id="id".
Dynamic attribute names. Put an expression in square brackets to choose the attribute at runtime:
<template>
<button :[attrName]="attrValue">Go</button>
</template>
The expression must resolve to a string (or null to bind nothing); it is lower-cased by the browser, so
avoid uppercase and whitespace in it.
Binding an object of attributes. v-bind with no argument spreads every own property of an object onto the
element — useful for forwarding a bag of props or DOM attributes:
<script setup>
const attrs = { id: 'main', 'data-role': 'panel', tabindex: 0 }
</script>
<template>
<section v-bind="attrs">...</section>
</template>
Expressions in bindings, and their limits
Each binding holds one JavaScript expression — something that could sit after return. It is evaluated in
a sandbox with access to the component’s template scope plus a short allowlist of globals (Math, Date,
JSON, and a few more).
<template>
<p>{{ count + 1 }}</p>
<p>{{ message.split('').reverse().join('') }}</p>
<p :class="isActive ? 'on' : 'off'"></p>
</template>
What is not allowed: statements (if, for, variable declarations), flow control (use the ternary
operator or a computed property instead), assignment as the whole expression, and arbitrary user globals such
as window or fetch. When logic grows past a readable one-liner, move it into an
computed property or a method.
Anatomy of a directive
A directive is a template attribute whose name starts with v-. Its value is a single expression, except for
a few (v-else, v-pre) that take none. The full grammar:
v-on : click .prevent .once = "handler"
│ │ │ │
name argument modifiers value
-
Name —
v-on,v-bind,v-if,v-for,v-model, … the directive to apply. -
Argument — after the colon, names the target: the event for
v-on:click, the attribute forv-bind:href, the slot forv-slot:header. -
Dynamic argument — wrap the argument in square brackets to compute it:
v-on:[eventName],v-bind:[attrName]. -
Modifiers — dot-prefixed flags that adjust behaviour:
.preventcallsevent.preventDefault(),.stopstops propagation,.oncedetaches after one call,.number/.trim/.lazyshapev-model.
Shorthands
Three directives are common enough to have a one-character form:
| Directive | Shorthand | Example |
|---|---|---|
|
|
|
|
|
|
|
|
|
The shorthands are the idiomatic form; the long v- names appear mostly in documentation.
Binding class
:class accepts more than a string, and its result is merged with any static class on the same element.
See Class and Style Bindings.
Object syntax — keys are class names, values decide whether each is present:
<template>
<div class="card" :class="{ active: isActive, 'is-error': hasError }">...</div>
</template>
Rendered as class="card active" when isActive is truthy and hasError is not. The object can be a
reactive object or a computed property returning one.
Array syntax — a list of class names or expressions; nest an object for conditional entries:
<template>
<div :class="[baseClass, isActive ? 'active' : '', { disabled: isDisabled }]">...</div>
</template>
On a component — a class set by the parent is added to the component’s single root element (it does not
replace the classes the component sets on itself). This is part of fallthrough attribute behaviour; with
multiple root elements you direct it with :class="$attrs.class".
Binding style
Object syntax — the natural form. Property names may be camelCase or the CSS kebab-case (quoted):
<script setup>
import { ref } from 'vue'
const activeColor = ref('teal')
const fontSize = ref(14)
</script>
<template>
<p :style="{ color: activeColor, fontSize: fontSize + 'px' }">...</p>
<p :style="styleObject">bind a whole reactive object</p>
</template>
Auto-prefixing — when a CSS property needs a vendor prefix, Vue adds the right one at runtime after testing the current browser.
Multiple values — give an array for a property and Vue keeps the last value the browser accepts, letting you ship a fallback:
<template>
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">...</div>
</template>
Array syntax on :style itself merges several style objects onto one element:
<template>
<div :style="[baseStyles, overrideStyles]">...</div>
</template>
See also
-
Reactivity Fundamentals — the reactive state that bindings read.
-
Computed Properties — where non-trivial binding logic belongs.
-
Conditional and List Rendering —
v-if,v-showandv-for. -
Security and Accessibility —
v-htmland template-injection risks. -
HTML & CSS Reference — the HTML attributes and CSS properties being bound.