Back
Keentune
Vue curriculum 26 chapters
·
222 concepts
·
free
Everything the adaptive question bank can teach and test in Vue, from foundations through advanced practice. Work through it in order, or start practicing and let the questions find your level.
Start practicing Vue
New here? Read the Vue guide A free 18-minute primer — the mental model, the mistakes beginners make, and what to practice first.
A. The application instance and what an SFC is •
createApp(Root) builds an app object; nothing renders until .mount() is called.
•
.mount('#app') replaces the container's inner HTML and returns the root component instance.
•
app.config.globalProperties and app.config.errorHandler apply to that app only, not to Vue itself.
•
The runtime-only build cannot compile a string template; only the full build ships the compiler.
•
An SFC is <template> , <script setup> and <style> compiled into one component module.
Practice this section →
B. Template syntax •
{{ }} inserts escaped text and accepts exactly one expression.
•
A binding holds an expression; if and var are syntax errors while a ternary is fine.
•
v-html writes raw HTML, so it must never receive user input.
•
A directive is v-name:arg.modifier="value" , and only the value is evaluated as JavaScript.
•
:[key]="v" computes the attribute name at runtime; it must resolve to a string or null.
•
: is v-bind, @ is v-on, # is v-slot.
•
Binding null or undefined removes the attribute rather than printing the word.
•
:id with no value binds the in-scope variable named id (3.4+).
•
Expressions see only an allow-list of globals such as Math and Date ; window is not exposed.
Practice this section →
C. Built-in directives: conditionals, lists, class and style •
V-if creates and destroys, running child lifecycle hooks; v-show only toggles display .
•
V-show does not work on <template> and has no v-else counterpart.
•
v-else and v-else-if must be on the immediately following sibling element.
•
V-for walks arrays, strings, plain objects as (value, key, index) , and an integer range starting at 1.
•
The key must be a stable primitive; using the index corrupts state when the list reorders.
•
On one element Vue 3 evaluates v-if first, so it cannot see the v-for alias.
•
<template v-for> repeats several nodes per item without introducing a wrapper element.
•
Mutating methods update in place; map / filter return a new array that must be assigned.
•
:class takes a string, a condition object, or an array, and merges with the static class .
•
:style accepts camelCase or kebab keys, auto-prefixes, and takes an array of values as fallbacks.
•
V-once renders a subtree one time; v-pre tells the compiler to skip the subtree entirely.
Practice this section →
D. Reactivity fundamentals •
ref() boxes any value; script code reads and writes .value .
•
reactive() hands back a Proxy, so the proxy is not === the original object.
•
reactive() ignores primitives; only objects, arrays, Map and Set become reactive.
•
Assigning a new object to a reactive variable abandons the proxy every dependency tracked.
•
Pulling a primitive out of a reactive object copies its current value and stops updating.
•
A ref is auto-unwrapped in the template only when it is a top-level property of the render scope.
•
A ref stored on a reactive object unwraps on read, and assignment writes through to .value .
•
Refs inside arrays, Map values or plain objects are not unwrapped; .value is required.
•
Reactive conversion is deep by default, converting nested objects as they are accessed.
•
Putting an object into a ref makes it deeply reactive through reactive() .
•
Several mutations in one tick produce one re-render; nextTick() waits for the flushed DOM.
Practice this section →
E. Computed properties •
A computed re-evaluates only when a dependency changes; a method re-runs on every render.
•
A getter must not mutate state, fetch, or touch the DOM.
•
Sort or reverse a copy, because the array methods mutate in place.
•
The get/set form; the setter receives the assigned value and must write back to the sources.
•
computed() yields a ref, so .value in script and auto-unwrapped in the template.
•
Reading a plain variable in a getter never invalidates the cache.
•
The getter's first argument is the previously computed value (3.4+).
Practice this section →
F. Event handling •
A method name receives the native event; an inline statement needs $event or an arrow function.
•
.stop , .prevent , .self , .capture , .once and .passive , applied in the order written.
•
.self only checks that the target is this element; .stop halts propagation.
•
@keyup.enter and kebab-cased key aliases, with .exact pinning the modifier combination.
•
.ctrl , .alt , .shift and .meta require that key to be held while the event fires.
•
.passive promises not to cancel, so combining it with .prevent is a mistake.
Practice this section →
G. Form input bindings •
V-model expands to a value binding plus an input or change handler chosen by element type.
•
A static value , checked or selected in the markup is ignored; the bound state wins.
•
Several checkboxes bound to one array collect their value s into it.
•
Replaces the boolean a single checkbox writes.
•
.lazy syncs on change, .number casts and falls back on NaN, .trim strips surrounding whitespace.
•
V-model deliberately skips updates during IME composition; a raw @input listener does not.
Practice this section →
H. Lifecycle hooks and template refs •
The <script setup> body runs before mount and has no this .
•
The element tree exists at onMounted, not in setup.
•
A hook registered after an await cannot bind to the current instance.
•
Timers, listeners and subscriptions leak unless torn down here.
•
onBeforeUpdate and onUpdated fire per re-render, and mutating state inside onUpdated can loop forever.
•
Children mount before their parent, and unmount before it too.
•
A template ref is null before mount and null again after unmount.
•
A template ref on a repeated element collects an array whose order is not guaranteed.
•
onErrorCaptured, plus the development-only onRenderTracked and onRenderTriggered.
Practice this section →
I. Watchers •
A ref, a getter function, a reactive object, or an array of those.
•
Watching a reactive object watches it deeply, so old and new value are the same object.
•
watch(obj.count, …) passes a plain number; wrap it as () => obj.count .
•
deep: true traverses the whole tree on every change and can dominate the update.
•
Fires the callback once at creation with the current value.
•
The watcher stops itself after the first callback (3.4+).
•
watchEffect runs immediately and subscribes to whatever it read during that run.
•
Dependencies accessed after an await inside the effect are not tracked.
•
pre runs before the render, post after the DOM updates, sync on every change.
•
The cleanup runs before the next invocation and on stop, which is how a stale request is canceled.
•
A watcher created in setup stops with the component; one created asynchronously must be stopped by hand.
•
A watcher exists for side effects; derived state belongs in a computed.
Practice this section →
J. Components: registration, instances, dynamic components •
app.component() registers everywhere and defeats tree-shaking; local registration does not.
•
PascalCase works in SFCs, while in-DOM templates must use kebab-case.
•
Every occurrence gets its own state, which is why data in the Options API is a function.
•
Vue 3 allows a fragment root, and that changes how attributes fall through.
•
<component:is> accepts a component object, a registered name, or an HTML tag string.
•
A component may render itself by name, and needs a condition that terminates.
Practice this section →
K. Props and attribute fallthrough •
Only declared props become props; anything else lands in the fallthrough attributes.
•
Declare camelCase, pass kebab-case in templates.
•
A prop is read-only, and writing to it warns and is overwritten on the parent's next render.
•
Mutating an object prop's fields does not warn but still couples child to parent.
•
Object and array defaults must come from a function or every instance shares one value.
•
A bare attribute becomes true and an absent one false , unless the declared type union changes the cast.
•
Custom validators and type checks warn in dev and are stripped from production.
•
v-bind="obj" spreads each key as its own prop.
•
Destructured props stay reactive from 3.5; before that they must be kept as toRefs .
•
Undeclared attributes and listeners are applied to the single root element automatically.
•
A fallthrough class merges with the child's own class instead of replacing it.
•
Turns the automatic fallthrough off so v-bind="$attrs" can target an inner element.
•
With several root nodes Vue warns unless $attrs is bound explicitly.
Practice this section →
L. Component events and v-model •
defineEmits documents the contract and removes that listener from $attrs .
•
$emit('name', payload) and the parent handler receiving it as the first argument.
•
Declare camelCase and listen in kebab-case; unlike props, emitted names are not transformed for you.
•
A component event reaches only the direct parent; anything further needs a re-emit or provide.
•
An undeclared @click on a component attaches to its root element instead.
•
v-model on a component is the modelValue prop plus the update:modelValue event.
•
v-model:title maps to the title prop and the update:title event, and several can coexist.
•
defineModel() returns a writable ref that declares both the prop and the event (3.4+).
•
A custom modifier arrives in modelModifiers and the child decides what it means.
Practice this section →
M. Slots •
<slot> marks where the parent's content is rendered.
•
Slot content is compiled in the parent's scope and cannot read the child's state.
•
Markup inside <slot> shows only when the parent passed nothing.
•
v-slot:name or #name on a <template> ; leftover content becomes the default slot.
•
The child binds props on <slot> , and the parent destructures them in v-slot="{ x }" .
•
Mixing a scoped default slot with named slots requires an explicit <template #default> .
•
#[name] resolves which slot to fill at runtime.
•
$slots.name is truthy only when the parent supplied it, so a wrapper can be skipped.
•
A component that renders nothing but a scoped slot ships behavior without markup.
Practice this section →
N. Provide and inject •
An ancestor provides a key and any descendant injects it, skipping the intermediate props.
•
app.provide() makes a value visible to every component in that app.
•
A Symbol key avoids name collisions and carries the type in TypeScript.
•
The second argument is a default, and a third true marks it a factory.
•
Provide a ref or computed; a plain value never updates its consumers.
•
Provide an updater function so writes stay in the providing component.
•
Wrapping the provided ref in readonly() stops descendants from writing to it.
Practice this section →
O. Built-in components: Transition, KeepAlive, Teleport, Suspense •
<Transition> animates one element or component entering and leaving.
•
v-enter-from , v-enter-active , v-enter-to and the mirrored leave classes.
•
name="fade" renames every class from the v- prefix to fade- .
•
It reacts to v-if, v-show or a changing <component:is> , not to a data change alone.
•
Without a mode both elements exist at once and the layout jumps.
•
TransitionGroup animates a list, requires keys, and adds the v-move class for repositioning.
•
The JavaScript hooks, with :css="false" telling Vue to skip class detection.
•
KeepAlive caches a toggled component's state and DOM instead of destroying it.
•
Cached components get onActivated and onDeactivated rather than mount and unmount.
•
Matching is by component name , and max evicts the least recently used.
•
The node is relocated but props, provide and emitted events still follow the logical parent.
•
Renders in place instead, which is how a modal degrades on mobile.
•
A loader returning a Promise, with optional loading and error components, delay and timeout.
•
The bundle splits only when the loader is a real dynamic import.
•
<Suspense> shows its fallback until every async dependency resolves, and is still experimental.
Practice this section →
P. Composables •
A composable is an ordinary function that uses the reactivity APIs, named useX .
•
Calling it at the top of setup is what binds its lifecycle hooks and effect scope.
•
Each call creates fresh state; state declared at module scope is shared by every caller.
•
Return refs so the caller keeps reactivity after destructuring the result.
•
Normalize the argument with toValue() so a ref, a getter or a plain value all work.
•
Pair every listener or timer with an onUnmounted so repeated use does not leak.
•
Explicit sources and no silent key collisions, which is why mixins are discouraged in Vue 3.
Practice this section →
Q. Custom directives and plugins •
Created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted.
•
The hook receives value , oldValue , arg , modifiers and the owning instance.
•
A bare function is registered for the mounted and updated hooks.
•
A variable named vFocus is usable as v-focus with no registration step.
•
A directive applied to a component lands on its single root and warns on a fragment.
•
A plugin is an object with install(app, options) , or a function, applied via app.use() .
Practice this section →
R. Reactivity in depth and the advanced APIs •
Vue 3 traps get and set on a Proxy, so added and deleted keys are reactive without a helper.
•
The Vue 2 mechanism could not observe new properties or index assignment.
•
A getter records the currently running effect; a setter re-runs the effects that recorded.
•
A component's render function is itself an effect, which is why reading a ref subscribes that component.
•
Only replacing .value triggers; mutating inside the value does not.
•
Forces subscribers of a shallowRef to run after an in-place mutation.
•
Only root-level properties are reactive and nested objects stay raw.
•
Opting an object out of proxying, and recovering the original object from a proxy.
•
Takes explicit control of when tracking and triggering happen, as a debounced ref does.
•
Groups effects so one .stop() disposes watchers created outside a component.
•
Converting a reactive object into refs that survive destructuring, with toRef also wrapping a getter.
•
A readonly proxy warns on write and is a different object from its source.
Practice this section →
S. The rendering mechanism and render functions •
A render produces a virtual node tree that is patched against the previous tree.
•
The compiler marks which bindings on a node can change, so the diff skips the static parts.
•
Nodes with no bindings are created once at module scope and reused across renders.
•
Dynamic descendants are collected in a flat array, making diff cost proportional to dynamic content.
•
A structural directive opens a new block because the node shape can change.
•
Skips patching a subtree while every value in its dependency array is unchanged.
•
Changing a component's key destroys and recreates it rather than patching in place.
•
h(type, props, children) builds a vnode, with children as a string, an array, or a slots object.
•
In a render function slots are passed as functions so they can be re-invoked on update.
•
Templates earn the compiler's optimizations; render functions and JSX trade them for full JavaScript control.
Practice this section →
T. Single-file components, <script setup> and TypeScript •
Top-level bindings are exposed to the template without an explicit return.
•
defineProps, defineEmits, defineExpose, defineOptions and defineModel are compiled away and are not imports.
•
A macro's argument may reference imports but not other <script setup> locals.
•
A <script setup> component is closed by default, so a template ref sees only what is exposed.
•
Permitted, and it turns the component into an async dependency of <Suspense> .
•
A plain <script> alongside <script setup> runs once at module scope, for named exports.
•
<style scoped> adds a data attribute, and a child's root element is still hit by the parent's scoped rules.
•
:deep() reaches into a child, :slotted() targets slot content, :global() escapes scoping.
•
v-bind() inside a style block compiles to a CSS custom property updated at runtime.
•
A type-only defineProps<T>() replaces the runtime declaration, with withDefaults supplying defaults.
•
generic="T" on <script setup> types props against a caller-supplied type parameter.
Practice this section →
U. Vue Router •
A route record maps a path to a component that renders inside <RouterView> .
•
createWebHistory needs a server catch-all rewrite; createWebHashHistory does not.
•
/user/:id exposes route.params.id , with modifiers for optional and repeatable segments.
•
Navigating between two params of the same route reuses the component, so setup does not run again.
•
Child routes render into the parent component's own <RouterView> .
•
Global beforeEach, then per-route beforeEnter, then the in-component guards.
•
Returning false cancels the navigation, returning a location redirects, returning nothing continues.
•
useRoute() is the reactive current location; useRouter() is the instance you navigate with.
•
A dynamic import in the route record splits the bundle per route.
Practice this section →
V. State management with Pinia •
defineStore(id, setup) returns a composable, and the id must be unique across the app.
•
Every useStore() call within one app returns the same store instance.
•
Calling a store before the Pinia plugin is installed throws.
•
Destructuring a store loses reactivity; storeToRefs keeps state and getters reactive while methods destructure freely.
•
In a setup store, ref is state, computed is a getter, and a function is an action.
•
$patch applies several changes as one entry for subscribers and devtools.
Practice this section →
W. Server-side rendering and hydration •
The server produces HTML and the client attaches to that existing DOM instead of rebuilding it.
•
If the client's first render disagrees with the server HTML, Vue warns and discards the markup.
•
Date.now() , Math.random() , locale formatting and invalid HTML nesting corrected by the parser.
•
Defer browser-dependent markup behind an onMounted flag or a client-only wrapper.
•
window and document do not exist on the server, so DOM access belongs in onMounted.
•
Module-scoped state is shared by every request; app and store must be created per request.
•
Only the creation hooks run; mount and update hooks never fire during a server render.
•
Server-fetched state is inlined into the page so the client does not refetch it during hydration.
Practice this section →
X. Performance, production builds and security •
Passing a freshly built object every render defeats the child's ability to skip updating.
•
The fix for a very long list is rendering fewer nodes, not a faster diff.
•
Avoid deep-proxying a big structure that is replaced wholesale.
•
The development build carries warnings and devtools hooks and must never be shipped.
•
v-html , dynamic :href , dynamic :style and <component:is> are the documented injection points.
•
Compiling a user-supplied template runs arbitrary JavaScript.
Practice this section →
Y. The Options API •
data is a factory so that each instance gets its own object.
•
Options methods bind this to the instance, which is why an arrow function in methods breaks.
•
The watch option keys on a dotted property path and accepts a method name as the handler.
•
Bindings returned from setup() are reachable from options, but not the reverse.
•
Mixin options merge with the component winning conflicts, and the resulting opacity is why mixins were deprecated in favor of composables.
Practice this section →
Z. Web components and custom elements •
Vue tries to resolve a non-native tag as a registered component first and warns "failed to resolve component"; compilerOptions.isCustomElement tells it to skip, and it is a compile-time option so it belongs in the build config.
•
Attributes can only be strings, so complex data goes as a DOM property; Vue checks with the in operator and prefers the property, and .prop forces it when the element does not reflect one.
•
defineCustomElement takes the same argument as defineComponent but returns a constructor extending HTMLElement , which customElements.define then registers.
•
Naming a file .ce.vue collects its CSS into a styles option that defineCustomElement injects into the element's shadow root.
•
An emitted event is dispatched as a native CustomEvent , and the payload arrives as an ARRAY on its detail .
•
Inside the component <slot/> works as usual, but a consumer gets native slot syntax only: the slot attribute rather than v-slot , and no scoped slots.
•
provide/inject works between Vue-defined custom elements, but one cannot inject from a plain Vue component ancestor.
Practice this section →
Keentune is not affiliated with or endorsed by the organizations whose documentation informs these maps.
Start practicing Vue
All about Vue practice
Browse all free study guides
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.
© 2026 SportaApp LLC