The first five Essentials chapters define the vocabulary every other chapter uses. Interviewers rarely ask about them directly, but they catch gaps through them: a candidate who does not know that a ref only unwraps at the top level of a template, or that v-bind can bind a whole object, or that a computed getter must be side-effect free, is telling the interviewer where to dig.
createApp(RootComponent) returns an application instance; app.mount('#app') renders the root component into the container and returns the root component instance. Mount last, after registering components, directives and plugins.app.config holds app-level options: errorHandler, warnHandler, performance, compilerOptions, globalProperties (the Vue 3 replacement for Vue.prototype), optionMergeStrategies, idPrefix (3.5), throwUnhandledErrorInProduction (3.5).app.component('TodoItem', TodoItem), app.directive(...), app.use(plugin), app.provide(key, value).template, Vue uses the container's innerHTML; that requires the full build with the compiler.{{ msg }} renders text, HTML-escaped. v-html renders raw HTML: never for user content (XSS), and it cannot compose templates.v-bind:id="id", shorthand :id, and same-name shorthand :id alone (3.4+) meaning :id="id". Boolean attributes (disabled) are included when the value is truthy or "" and omitted when falsy. v-bind="obj" binds several attributes at once.Math, Date, …); extend it through app.config.globalProperties. Functions called in bindings run on every update and must not have side effects.v- attributes whose value is an expression; arguments follow a colon (v-on:click, shorthand @click), dynamic arguments use brackets (:[attrName], must evaluate to a string or null; no spaces or quotes, and lowercase in in-DOM templates), modifiers follow a dot (@submit.prevent).ref() wraps a value in an object with .value; refs unwrap automatically in templates, but only top-level refs: {{ object.id + 1 }} does not unwrap object.id if id is a ref, while {{ object.id }} alone does (final value of a text interpolation unwraps).shallowRef opts out for the nested levels.await nextTick() to read the updated DOM.reactive() returns a Proxy of an object (objects, arrays, Map, Set); reactive(raw) !== raw, calling it twice on the same raw returns the same proxy, and nested objects are proxied on access. Limitations: only object types; cannot be replaced (the reference is lost); destructuring copies plain values.{ get, set }. Previous value (3.4+): the getter receives the previous value as its argument.Object.is), so returning a new object every time defeats that optimisation.:class accepts a string, an object ({ active: isActive }), or an array (which may contain objects and ternaries); it merges with the static class.:class="$attrs.class".:style accepts an object (camelCase or quoted kebab-case keys) or an array of objects; Vue auto-prefixes vendor properties and accepts an array of values for one property (display: ['-webkit-box', '-ms-flexbox', 'flex']), rendering the last supported one.The facts above in one component:
<script setup lang="ts">
const id = 'title-field'
const title = ref('Hello')
const state = reactive({ count: 0, tags: [ref('a')] }) // refs inside arrays are NOT unwrapped
const attrs = { placeholder: 'Type…', maxlength: 40 }
const isActive = ref(true)
const size = ref<'sm' | 'lg'>('sm')
// Cached: recomputes only when title changes; receives the previous value since 3.4
const shout = computed(prev => (title.value ? `${title.value.toUpperCase()}!` : prev ?? ''))
// Writable computed
const upper = computed({
get: () => title.value.toUpperCase(),
set: v => { title.value = v.toLowerCase() },
})
</script>
<template>
<!-- :id same-name shorthand (3.4+), object binding, boolean attribute, dynamic argument -->
<label :for="id">Title</label>
<input :id v-model="title" v-bind="attrs" :disabled="!isActive" :[isActive ? 'data-on' : 'data-off']="''">
<p>{{ shout }} / {{ upper }} / {{ state.count }} / {{ state.tags[0].value }}</p>
<!-- class object + array, style object with auto-prefixing -->
<div :class="[{ active: isActive }, `size-${size}`]" :style="{ display: 'flex', userSelect: 'none' }" />
</template>
const obj = { count: ref(0) } (a plain object) then {{ obj.count + 1 }} renders [object Object]1, because obj.count is not a top-level ref and the expression is not a bare interpolation. Destructure to top level (const { count } = obj) or make obj reactive.
[object Object]1 bug and fix it both ways.'', false, null and 0 and inspect the rendered DOM each time.console.count while an unrelated ref changes."Refs unwrap in templates only when they are top-level properties of the setup scope, or when the whole interpolation evaluates to the ref; {{ obj.count + 1 }} with a nested ref does not unwrap. Inside a reactive object a ref property is unwrapped and assigning a new ref to it replaces the old one, but refs inside reactive arrays and collections such as Map are left as refs and need .value. Knowing those three cases explains most 'it renders object Object' bugs."
Nothing yet. Notes filed here show up on this page and the section overview.
Vue docs, chapter by chapter
How to use this section to learn the official Vue guide thoroughly enough to be quizzed on it, and how it relates to the senior-depth Vue section.
Essentials II — rendering, events and forms
Conditional and List Rendering, Event Handling, Form Input Bindings, Watchers, Template Refs, Components Basics and Lifecycle Hooks, as the guide states them.