Vue.js
Vue 3's core framework: SFCs, templates, Proxy-based reactivity, the Composition and Options APIs, rendering, SSR, typing and testing. Interviewers probe how tracked reads drive precise updates.
on this pageshowhide
guide
overview
~2 minVue is a UI framework built on two ideas that interviewers keep coming back to: templates compiled ahead of time into render functions, and a reactivity system that records which state each piece of code reads. Nearly every Vue question, from a junior's choice between `v-if` and `v-show` to a principal's server-rendering design, ends up asking whether you know what Vue is tracking and when it acts on a change. A good answer names the mechanism, its timing, and the case where it quietly stops working. The hub splits along the way a component is built and run. [Single-file components](/topics/fe-vue-sfc) and [template syntax](/topics/fe-vue-directives-template) are the surface you write every day. [The reactivity system](/topics/fe-vue-reactivity) sits beneath all of it, with [computed values and watchers](/topics/fe-vue-computed-watchers) as the tools that derive from state and react to it. Components are authored with the [Composition API](/topics/fe-vue-composition-api) or the older [Options API](/topics/fe-vue-options-api), expose a [public interface](/topics/fe-vue-components) of props, events, `v-model` and slots, and pass through [lifecycle hooks](/topics/fe-vue-lifecycle). [Runtime built-ins](/topics/fe-vue-builtins) and the [application instance](/topics/fe-vue-app) cover what Vue ships around components. [The rendering mechanism](/topics/fe-vue-rendering) and [speed and bundle tuning](/topics/fe-vue-performance) explain what happens after a change, [server-side rendering](/topics/fe-vue-ssr) runs the same code in two places, and [type safety](/topics/fe-vue-typescript), [component testing](/topics/fe-vue-testing) and [upgrading from Vue 2](/topics/fe-vue-migration) complete the working engineer's side. Junior rounds check template fluency, `ref` against `reactive`, and where a listener is removed. Middle rounds move to watch sources, component contracts and update timing. Senior and principal rounds turn into trade-offs and incident stories: a hydration mismatch, a list that re-renders far too often, a codebase caught halfway through a Vue 2 upgrade. Start with single-file components and templates so the syntax stops being noise, then the reactivity system, then computed values and watchers. The component interface and the Composition API build on those three; rendering, performance and SSR make sense once you can say what a component's render depends on.
primer
### Reads are subscriptions Vue does not diff your state, and it does not ask you to list dependencies. When an effect runs — a component's render, a `computed`, a watcher — every reactive property it reads records that effect as a subscriber, and a later write to one of those properties schedules it again. That is why updates are precise, and why most reactivity bugs are the same bug in different clothes: a read that happened where Vue could not see it. A plain `let`, a value copied out of a proxy, a prop handed to a watcher as a value — each is data Vue has lost track of. Explaining such a bug in an interview usually means naming the read that went untracked. ### Two containers, one system `ref()` holds any value behind `.value`; `reactive()` returns a proxy of an object. Both sit on the same tracking machinery, so the choice between them is about ergonomics and failure modes, not power. Most Vue 3 code leans on `ref`, and you are expected to say why — including what happens to a reactive object when it is destructured or reassigned. The shallow and raw variants exist to keep large or foreign data out of deep tracking. ### Updates are batched A write only marks work as pending. Vue runs the queued updates together shortly afterwards, once per tick, however many writes happened. State changes synchronously; the DOM catches up later. Code that measures layout, tests that assert on markup, and watchers that choose their `flush` timing all live in that gap. ### Derive, don't synchronise `computed` values are cached derivations; watchers are for side effects such as fetching, persisting or touching the DOM. A watcher whose only job is to copy one piece of state into another is the classic sign that a computed was the right tool, and interviewers use it to tell people who have written Vue from people who have maintained it. ### Setup runs once The body of `<script setup>` or `setup()` runs a single time for each component instance, not on every render. That is the sharpest contrast with React hooks: no call-order rules, fewer stale-closure traps, but lifecycle hooks and `inject` must be called while setup is running synchronously. A composable is an ordinary function called inside that window, which is how it gets to own state and lifecycle. ### A component is a contract From outside, a component is props going in, emitted events coming out, `v-model` as a convention built from the pair, attributes that fall through to the root, and slots through which the parent supplies markup. One-way data flow — the child asks, the owner changes — is the rule most component-design questions test. ### The compiler is half the framework Templates are compiled into render functions, and the compiler marks what can change: static content is hoisted, dynamic bindings are flagged, so the runtime skips comparisons a naive virtual DOM would repeat. Many performance and "why did this re-render" questions are really about what the compiler could prove and what it could not.
- Single-file component (SFC)
- A .vue file combining template, script and style blocks, which build tooling compiles into a component module, optionally with scoped CSS.
- Script setup
- The SFC syntax in which a script block's top-level code becomes the component's setup logic, with its bindings visible to the template without being returned.
- Compiler macro
- A call such as defineProps, defineEmits or defineModel that exists only at compile time inside script setup and needs no import.
- ref
- A reactive container holding any value under a .value property; reading it is tracked and assigning it notifies subscribers.
- reactive
- A function returning a deep Proxy of an object that tracks property reads and writes. It cannot wrap primitives, and the proxy is not identical to the original object.
- Effect
- A function Vue re-runs when reactive data it read has changed. Component renders, computed values and watchers are all built on effects.
- Dependency tracking
- Recording, while an effect runs, which reactive properties it reads, so that only writes to those properties schedule it again.
- Computed
- A cached, lazily evaluated derived value that is recalculated only after one of the reactive values it read has changed.
- Watcher
- A callback created with watch or watchEffect that runs a side effect when its reactive sources change, with configurable timing relative to rendering.
- nextTick
- A function returning a promise that resolves once Vue has applied the DOM updates currently waiting in its queue.
- Composable
- A function, conventionally named useSomething, that packages stateful logic with Composition API calls and is called during a component's setup.
- Provide and inject
- A pair of APIs letting an ancestor supply a value that any descendant can receive, without the components in between passing it along.
- Fallthrough attributes
- Attributes and listeners a parent passes that the child declares neither as props nor as emits; by default they land on the child's root element.
- Scoped slot
- A slot through which the child passes data back to the parent's slot content, so the parent decides how that data is rendered.
- Vnode
- A lightweight JavaScript object standing for an element, component or text node. Render functions return trees of them for the renderer to turn into DOM.
- Patch flags
- Hints the template compiler attaches to vnodes marking which parts are dynamic, so the renderer compares only those parts during an update.
- Hydration
- Attaching a client-side Vue app to server-rendered HTML by adopting the existing DOM and adding listeners, instead of rendering from scratch.
Follow one change from a click to the screen. An event handler bound in the template writes to a ref. The ref's setter notifies every effect that read it: a computed marks itself stale, a watcher is queued, and the component's render effect is queued too. Shortly afterwards Vue flushes the queue. Watchers with the default timing run first; then the component re-runs its compiled render function, the renderer compares the new vnode tree against the last one and patches only what differs, skipping children whose props did not change. Post-flush work — `onUpdated`, post-flush watchers, code awaiting `nextTick()` — sees the finished DOM. The rest of the hub attaches to that loop rather than sitting beside it: - **SFCs and template syntax** are the compiler's input: `<script setup>` becomes the setup function, scoped styles become attribute selectors, directives become render-function code. - **The Composition and Options APIs** are two ways of creating the same reactive state and effects; the Options API keeps it on `this`. - **Lifecycle hooks** are named points in the mount, update and unmount phases of the loop. - **Built-ins** bend it: KeepAlive deactivates instead of unmounting, Teleport moves the DOM but not the component's place in the tree, Transition delays removal, Suspense waits on async setup. - **The application instance** holds what the whole tree shares: plugins, global components, app-level provides and error handlers. - **SSR** runs setup and render on the server to produce HTML, then the browser runs them again to hydrate; anything that differs between the two runs surfaces as a mismatch. - **TypeScript** support follows the compiler macros, and **testing** mounts a component and must wait for the same flush. Three effects meet in one small component: ```vue <script setup lang="ts"> import { ref, computed, watch } from 'vue' import { fetchCart, type Line } from './api' const props = defineProps<{ userId: string }>() const lines = ref<Line[]>([]) const total = computed(() => lines.value.reduce((sum, l) => sum + l.price * l.qty, 0)) watch(() => props.userId, async (id) => { lines.value = await fetchCart(id) }, { immediate: true }) </script> <template><p>Total: {{ total }}</p></template> ``` The render reads `total`, `total` reads `lines`, and the watcher reads `props.userId` through a getter. Each re-runs only when what it read changes. Pass the prop's current value instead of the getter and the watcher has nothing to follow; swap the computed for a method and the template recalculates on every render of the component.
- Single-File Components →
The file format every example uses: template, script setup and scoped styles, and what the compiler makes of them.
- Template Syntax →
Interpolation, conditionals, lists, bindings and events: the fluency check that opens most junior rounds.
- Reactivity System →
The tracking model under everything else: ref and reactive, lost reactivity, and when the DOM actually updates.
- Computed & Watchers →
How to derive state and run side effects from it, and when a watcher should have been a computed.
- Component Interface →
A component's public contract: props, emitted events, v-model, fallthrough attributes and slots.
- Composition API →
Setup, composables and provide/inject: how logic is organised and reused once the basics are in place.
Destructuring a
reactive()object into local variables and expecting them to stay live — see Destructuring & Ref Conversion.Writing a watcher that copies one piece of state into another when a
computedwould derive it without creating a second source of truth.Treating
:keyonv-foras a way to silence a warning, or keying by index, then meeting inputs and child state that stick to the wrong row after a reorder.Reading layout straight after a state change and calling the stale value a Vue bug, instead of recognising the batched update and waiting for
nextTick().Calling
onMountedorinjectafter anawaitinsidesetup(), when no component instance is current any more and the registration is lost.Mutating a nested field of a prop object because nothing stops you: the parent's state changes behind its back and one-way data flow is gone.
Touching
window,documentorlocalStorageat the top level of setup in an SSR app — see SSR-Safe Code.Describing Vue 3 with Vue 2's reactivity caveats, such as needing
Vue.setfor new keys, which Proxy-based tracking removed.Reaching for
v-memoorshallowRefbefore profiling shows which component re-renders and why.
This guide assumes Vue 3.5. Vue 2 reached end of life at the end of 2023, but upgrades and long-lived codebases still produce questions, and many answers carry a "since 3.x" clause: - **3.0** introduced Proxy-based reactivity, the Composition API, multiple root nodes, Teleport and an experimental Suspense, and moved global APIs such as `use` and `component` onto the app instance. - **3.2** made `<script setup>` stable and added `v-memo` and `effectScope`. - **3.3** added generic components, imported types in `defineProps`, and `defineOptions`. - **3.4** made `defineModel` stable and removed the experimental Reactivity Transform. - **3.5** made props destructured from `defineProps` in `<script setup>` reactive, and added `useTemplateRef`, `useId`, `onWatcherCleanup` and lazy hydration strategies for async components. The 3.5 destructuring change is a common source of disagreement: before it, destructured props were plain snapshots, and a candidate who learned on an older version will say so. Suspense is still marked experimental. When an answer depends on these — how `v-model` is authored, whether a destructured prop tracks, how a template ref is obtained — say which version you are describing.
Vue's official libraries cover what the core leaves out: Vue Router for routing, Pinia for shared application state as the recommended successor to Vuex, Vite for the dev server and builds, Vue Test Utils for mounting components under a test runner such as Vitest, and the Vue language tools with `vue-tsc` for type-checking templates. Nuxt is the full-stack framework built on top, adding file-based routing, data-fetching conventions and server rendering; this hub's [server-side rendering](/topics/fe-vue-ssr) section stays at the level of what the `vue` package provides on its own. Among UI frameworks Vue is usually weighed against React, Angular and Svelte. Against React the separating trade-off is tracked reactivity with compiled templates versus component functions that re-run on each render and are skipped only when you memoise them. Angular is a larger, more opinionated framework with dependency injection, routing and forms in one package, where Vue keeps a small core and adds official libraries. Svelte, like Vue, leans on a compiler, but pushes more of the work to build time. Interviewers rarely want a verdict; they want the Vue side of the comparison stated precisely, and the [Composition API](/topics/fe-vue-composition-api) section is where the comparison with React hooks lives.
explore
- Single-File Components16 questions
- SFC Blocks & Compilation5 questions
- Script Setup6 questions
- Scoped & Module Styles5 questions
- Component Interface31 questions
- Props Declaration & Validation5 questions
- Emitted Events5 questions
- Custom V-Model Binding5 questions
- Fallthrough Attributes4 questions
- Named & Scoped Slots4 questions
- Global vs Local Registration4 questions
- Dynamic & Async Loading4 questions
- Template Syntax38 questions
- Interpolation & Expressions5 questions
- V-If & V-Show4 questions
- Looping with V-For4 questions
- Class, Style & Attribute Binding5 questions
- Event Listeners & Modifiers5 questions
- Form Input Bindings5 questions
- Custom DOM Directives5 questions
- Element & Child Refs5 questions
- Reactivity System29 questions
- Ref vs Reactive4 questions
- Destructuring & Ref Conversion4 questions
- Shallow & Raw State4 questions
- Dependency Tracking Mechanics5 questions
- Proxy Identity & Collections4 questions
- Update Queue & Next Tick4 questions
- Effect Scopes4 questions
- Computed & Watchers17 questions
- Cached Derivations4 questions
- Watch Sources & Options5 questions
- WatchEffect & Flush Timing4 questions
- Cleanup & Stop Handles4 questions
- Composition API18 questions
- Setup Function4 questions
- Composables5 questions
- Provide & Inject4 questions
- Store-Free Shared State5 questions
- Options API13 questions
- Data, Methods & This4 questions
- Mixins & Extends4 questions
- Authoring Style Trade-offs5 questions
- Component Lifecycle Hooks13 questions
- Mount & Unmount Phases5 questions
- Update Phase Timing4 questions
- Synchronous Registration Rules4 questions
- Runtime Built-ins23 questions
- Enter & Leave Transitions5 questions
- TransitionGroup4 questions
- KeepAlive5 questions
- Teleport4 questions
- Suspense & Async Setup5 questions
- Application Instance23 questions
- CreateApp & Mounting5 questions
- App Config Options5 questions
- App-Wide Plugins4 questions
- Error Capture & Handlers4 questions
- Custom Elements Interop5 questions
- Rendering Mechanism17 questions
- Virtual DOM & Patching4 questions
- Compiler-Informed Optimizations4 questions
- Render Functions & JSX5 questions
- Runtime & Compiler Builds4 questions
- Speed & Bundle Tuning17 questions
- Update Optimizations5 questions
- Large Lists & Data4 questions
- Initial Load Cost4 questions
- Profiling & Debug Hooks4 questions
- Server-Side Rendering19 questions
- String & Stream Renderers5 questions
- Hydration Pitfalls5 questions
- SSR-Safe Code5 questions
- Lazy Hydration Strategies4 questions
- Type Safety20 questions
- Typing Props & Emits5 questions
- Typing Refs & Injection6 questions
- Generic Components4 questions
- SFC Checking Toolchain5 questions
- Component Testing17 questions
- Mounting & Stubbing5 questions
- Async Updates & Events4 questions
- Composables in Isolation4 questions
- Plugins & Providers in Tests4 questions
- Upgrading from Version 214 questions
- Removed & Changed APIs6 questions
- Getter-Setter Reactivity3 questions
- Compat Build & Rollout5 questions
questions
325 · 16 sectionsWhat top-level blocks can a Vue single-file component contain, and how many of each does the SFC format allow?
basics
~20 sA .vue file holds at most one <template>, one <script> and one <script setup>, any number of <style> blocks mixing scoped, module and global, and optional custom blocks such as <docs> that build tooling handles.
In a Vue single-file component, how does <style scoped> keep CSS local, and which outside elements can its rules still match?
basics
~20 sThe SFC compiler stamps a per-component data-v-<hash> attribute on the elements its template renders and appends that attribute selector to each scoped rule. A child component's single root element also carries it, so parent rules still reach it.
In a Vue 3 <script setup> component, how do top-level variables, functions and imports reach the template, and how often does that code run?
basics
~20 sEvery top-level binding in <script setup>, including variables, functions and imports, is usable in the template with no return object; imported components are used directly as tags. The block compiles into setup(), so it runs once per component instance.
What does a Vue .vue file become after @vue/compiler-sfc and the build step, and what happens to each of its blocks?
basics
~10 sA .vue file becomes a standard ES module default-exporting a component object: the template becomes a render function, script setup becomes setup(), and styles become plain CSS, injected in development or extracted in production.
In Vue 3's <script setup>, why are defineProps, defineEmits and the other define* macros never imported, and what restrictions follow from that?
basics
~20 sThe define* macros are compiler hints that @vue/compiler-sfc recognises and compiles away, so they need no import. Their arguments are hoisted to module scope, so they cannot reference variables declared in <script setup>, and they only work inside <script setup>.
In Vue 3, what can you bind to `<component :is>`, and what happens to a tab panel's local state when the tab switches?
basics
~20 sVue's <component :is> accepts an imported component object, a registered component name or an HTML tag name. Switching to a different component unmounts the old panel, so its local state is destroyed and returning mounts a fresh instance.
In a Vue 3 `<script setup>` component, how do you declare and emit a custom event, and how does the parent listen for it?
basics
~10 sCall defineEmits(['confirm']) at the top level of script setup, keep the returned emit function and call emit('confirm', id). The parent listens with v-on, @confirm="handler", and the handler receives the extra arguments.
In Vue 3, what happens to a class, style, id or @click listener a parent passes to a component that declares none of them?
basics
~10 sUndeclared attributes and v-on listeners are fallthrough attributes: Vue adds them to the component's single root element, merging class and style with the root's own values and running both listeners.
In a Vue 3 `<script setup>` component, how do you declare props with defineProps, and how do runtime and type-based declarations differ?
basics
~20 sdefineProps is a script setup compiler macro that declares props with either a runtime argument (a names array, or options with type, required, default and validator) or a TypeScript type argument compiled into runtime options; one call cannot take both.
In Vue 3, what is the difference between registering a component with app.component() and importing it locally in `<script setup>`, and which should you prefer?
basics
~20 sVue's app.component() registers a component app-wide, so any template can use it without importing, but it always ships in the bundle. A local import in script setup is visible only in that file and tree-shakes cleanly, so it is the default.
In Vue 3, how do :class object and array syntax work, and how would you build a button's classes from variant, size and disabled?
basics
~20 sVue's :class accepts a string, an object whose keys are added when their values are truthy, or an array of either. It merges with a static class attribute, so a computed can combine variant and size names with conditional flags like is-disabled.
In Vue 3, how do v-if and v-show differ, and which would you use for a dropdown versus a rarely opened admin panel?
basics
~20 sVue's v-if adds and removes its block, destroying child components and listeners, and renders nothing while false; v-show always renders and only toggles inline display. Use v-show for a frequently toggled dropdown, v-if for a rarely shown admin panel.
In Vue 3, what is the difference between a method handler and an inline handler in v-on, and how does each receive the native event?
basics
~20 sVue's template compiler treats a v-on value that is a name or property path (save, form.save) as a method handler, called with the native event. Anything else (save('draft'), count++) is an inline handler, where the event is available as $event.
In Vue 3, how does v-model on a checkbox behave when bound to a boolean versus an array, and what does the value attribute do?
basics
~20 sBound to a boolean, a checkbox's v-model stores true or false. Bound to an array or Set, each checked box adds its own value attribute to the collection and unchecking removes it, so every box in the group needs a distinct value.
In a Vue 3.5 `<script setup>` component, how do you focus an `<input>` on mount with a template ref, and why not during setup?
basics
~10 sPut ref="email" on the input, get it with useTemplateRef('email') (Vue 3.5) or a same-named ref(null), and call focus() in onMounted. During setup the element does not exist yet, so the ref is still null.
In Vue 3, why does `const { count } = reactive({ count: 0 })` stop updating, and how does `toRefs()` keep the link?
basics
~20 sDestructuring reads state.count once through the proxy and copies the number into a local variable, which Vue cannot track or update. toRefs(state) instead returns an object of refs, one per property, whose .value reads and writes state[key] through the proxy, so the link survives destructuring.
In Vue 3, what is the difference between ref() and reactive(), and why do the Vue docs recommend ref() as the primary API?
basics
~20 sref() wraps any value in an object whose .value getter tracks and setter triggers; reactive() returns a deep Proxy of an object itself. The docs prefer ref() because reactive() rejects primitives, cannot be replaced wholesale, and loses tracking when destructured.
In a Vue 3 component, why does measuring a list right after pushing an item return the old height, and how does nextTick() help?
basics
~20 sVue 3 does not patch the DOM when state changes; the write queues the component's update job, which runs in a microtask flush later. Awaiting nextTick() after the push waits for that flush, so the measurement sees the new item.
In a Vue 3 `<script setup>` component, why does `count++` on a plain `let count = 0` not update the template, while `count.value++` on a `ref` does?
basics
~20 sVue can only see reads and writes that pass through a property access it controls. A ref's .value getter calls track() and its setter calls trigger(), so the render effect subscribes and re-runs; a plain variable's reads and writes are invisible to Vue.
In Vue 3, a click handler assigns three different refs that one component renders; how many times does that component re-render, and why?
basics
~20 sOnce. Each write triggers the component's render effect, but its update job is already marked as queued after the first, so the later triggers are ignored; the single microtask flush re-renders once with all three new values.
In Vue 3, why use computed() for a cart total instead of a method called from the template?
basics
~20 scomputed() caches its result and re-runs its getter only after a reactive value it read has changed; a method called in the template has no cache and runs again on every re-render of the component.
In Vue 3, when does watchEffect() run its function, and which reactive reads become its dependencies?
basics
~20 sWith the default flush, watchEffect() runs its function immediately, and its dependencies are every reactive value read during that synchronous run. It re-runs when any of them changes, re-collecting dependencies each time, so conditional reads come and go.
In a Vue 3 `<script setup>` component, why does `watch(props.userId, cb)` never fire, and how should you watch the prop?
basics
~20 sprops.userId is read once and passes a plain value, not a reactive source, so Vue warns and tracks nothing. Pass a getter, () => props.userId, so the read happens inside the watcher where Vue can track it.
In Vue 3, which source forms does watch() accept, and how does each form decide whether the callback runs?
basics
~20 sVue 3's watch() accepts a ref, a reactive object, a getter function, or an array of these. A ref or getter fires when its value changes by Object.is; a reactive object is watched deeply; an array fires when any entry changes.
In Vue 3.5, what do watch() and watchEffect() return, and when would you stop, pause or resume a watcher yourself?
basics
~20 sThey return a WatchHandle: call it, or its stop(), to end the watcher for good, and since Vue 3.5 use pause() and resume() to suspend it. Watchers created synchronously in setup stop automatically on unmount, so manual stops are for other cases.
In Vue 3, what is a composable, and what separates it from an ordinary utility function such as a date formatter?
basics
~10 sA composable is a function, named useX by convention, that uses Vue's Composition API to encapsulate stateful logic: it creates its own refs, can hook into the calling component's lifecycle, and returns that state.
In a Vue 3 app, how do provide() and inject() get a layout's theme to deeply nested components without passing props?
basics
~20 sThe layout calls provide('theme', theme) in its setup; any descendant, however deep, calls inject('theme') in its setup to receive it. Components in between pass nothing, and only the provider's subtree can inject it; app.provide() makes a value available app-wide.
In Vue 3, what arguments does a component's setup() function receive, and what is it allowed to return?
basics
~20 sVue 3's setup(props, context) receives reactive, read-only props and a context with attrs, slots, emit and expose; it runs once per instance with no this, and returns an object of template bindings or a render function.
Why does Vue 3 recommend composables over mixins and renderless components for reusing stateful logic between components?
basics
~20 sComposables make every reused name explicit at the call site, resolve collisions by renaming and pass data between units as arguments, fixing mixins' three flaws, and unlike renderless components they add no extra component instance.
In Vue 3, why does an injected locale stop updating when the provider passes locale.value, and how should injectors change it?
basics
~20 sprovide('locale', locale.value) provides a plain string captured once, so later changes never reach injectors. Provide the ref itself, ideally wrapped in readonly(), plus a setLocale function, so injectors stay reactive and all changes happen in the provider.
What is the core difference between Vue 3's Options API and Composition API in how a component's code is organised?
basics
~20 sThe Options API groups code by option type (data, methods, computed, lifecycle hooks) on a this-based instance; the Composition API groups it by logical concern in one function scope. Both run on the same reactivity system.
In a Vue 3 Options API component, why do arrow functions break methods and lifecycle hooks, and what does method auto-binding give you?
basics
~20 sVue 3 binds every method and hook to the component instance, but an arrow function's this is fixed where it was written, so this is not the instance. Auto-binding means a method passed as a callback keeps its this.
In a Vue 3 Options API component, why must data be a function returning an object, and what does Vue make reactive?
basics
~20 sVue 3 calls data() once per component instance, so each instance gets its own state object. The result is wrapped with reactive() and its top-level keys are proxied on this; keys added later, or starting with _ or $, are not.
Why does the Vue 3 documentation recommend composables instead of mixins for sharing logic between components?
basics
~20 sThe Vue 3 docs name three mixin drawbacks: no way to tell which mixin added a property, silent collisions on shared keys, and coupling through shared keys. Composables return explicit values you name, rename and pass on.
Can a Vue 3 component use the Options API and the Composition API together, and what rules govern that mix?
basics
~10 sYes, through the setup() option: it runs before every options hook, and what it returns is available on this to options; setup() cannot read options, and <script setup> bindings never reach the Options API.
In a Vue 3 `<script setup>` component that listens to window resize events, where do you add and remove the listener, and why?
basics
~20 sAdd the listener in onMounted and remove it in onUnmounted (or onBeforeUnmount), passing the same function reference. Vue does not clean up listeners you attach to window yourself, so skipping the removal leaks the handler and everything it closes over.
In Vue 3, in what order do setup, onBeforeMount and onMounted run for a parent and its child, and how does unmounting order them?
basics
~10 sMounting goes parent setup, parent onBeforeMount, child setup, child onBeforeMount, child onMounted, then parent onMounted. Unmounting goes parent onBeforeUnmount, child onBeforeUnmount, child onUnmounted, then parent onUnmounted.
In Vue 3, why must onMounted and other lifecycle hooks be registered synchronously during setup, and what breaks after an await?
basics
~20 sVue 3 attaches each hook to the current component instance, which exists only while setup runs synchronously. After an await in async setup() none is current, so the hook is dropped with a dev warning; script setup restores top-level awaits.
In a Vue 3 `<script setup>` component, where should a data fetch start and where must a DOM measurement happen?
basics
~20 sA DOM measurement must wait for onMounted, because template refs are null until the component has rendered. A fetch needs no DOM, so it can start directly in setup, earlier than onMounted, as long as the component renders a loading state meanwhile.
In a Vue 3 <script setup> component, what happens when onMounted is registered twice, once directly and once inside a composable?
basics
~10 sVue 3 keeps a list per hook on the component instance, so both onMounted callbacks run, in the order they were registered during setup. A composable's hook attaches to whichever component called the composable.
In Vue 3, what changes when you wrap a tab's dynamic component in `<KeepAlive>` and the user leaves a half-filled long form and comes back?
basics
~20 sWithout KeepAlive, Vue unmounts the form's component when the tab switches away and builds a fresh one on return, losing every typed value. KeepAlive deactivates and caches the instance instead, so the same instance, state and DOM come back.
In Vue 3, how does the built-in `<Teleport>` fix a modal clipped inside a deeply nested scrolling container, and what does its `to` prop accept?
basics
~20 sVue's <Teleport> renders its slot content into another DOM node, typically body, so ancestor overflow, transforms and stacking contexts stop constraining the modal. Its to prop takes a CSS selector string or an actual DOM element.
In Vue 3, which six CSS classes does `<Transition>` apply to an entering and a leaving element, and when is each one added and removed?
basics
~20 sVue 3's Transition adds v-enter-from, v-enter-active and v-enter-to on insert, and v-leave-from, v-leave-active and v-leave-to on removal. The from class is swapped for the to class a frame later; the active class lasts the whole phase.
In a Vue 3 component cached by `<KeepAlive>`, when exactly do `onActivated` and `onDeactivated` run, and what work belongs in them?
basics
~20 sIn Vue 3, onActivated runs on the cached component's first mount and every time it is reinserted; onDeactivated runs each time it is moved into the cache and on final unmount. Use them for show/hide work: refresh, pause, resume.
In Vue 3, when a child component renders inside `<Teleport to="body">`, which relationships follow the component tree and which follow the DOM?
basics
~20 sVue relationships follow the component tree: props, emitted events, injections, Devtools nesting and reactivity work as without Teleport. Anything the browser computes from DOM position follows the target: native event bubbling, ancestor-based CSS selectors and contains() checks.
In Vue 3, how do you make a $formatCurrency helper available in every component template, and what Vue 2 mechanism did that replace?
basics
~20 sAssign it to app.config.globalProperties.$formatCurrency before mounting. It replaces Vue 2's Vue.prototype: templates and Options API this can read it, but a component's own property of the same name wins and script setup code cannot use this.
In Vue 3, what does app.mount() return, and why does createApp(App).mount('#app').use(plugin) fail?
basics
~20 sapp.mount() renders the root component into the container and returns the root component instance, not the app. That instance has no use() method, so chaining .use() after mount throws; configure and register everything first, then call mount last.
In Vue 3, what is a plugin, and what exactly happens when you call app.use(plugin, options)?
basics
~20 sA Vue 3 plugin is an object with an install(app, options) method, or a bare function used as install. app.use calls it synchronously with the app and any extra arguments, installs it once per app, and returns the app.
In Vue 3, what does `app.config.errorHandler` receive, which errors reach it, and what does Vue do with an error when no handler is set?
basics
~20 sVue 3's app.config.errorHandler receives (err, instance, info) for errors in renders, setup, hooks, watchers, event handlers and directive or transition hooks that no onErrorCaptured stopped. Without it, Vue rethrows in development and only logs in production.
In Vue 3, why does a native custom element like `<color-swatch>` trigger "Failed to resolve component", and how does `compilerOptions.isCustomElement` fix it?
basics
~20 sVue 3's compiler treats any non-native tag as a component and warns when none is registered. compilerOptions.isCustomElement, a tag-name predicate, makes it emit a plain element instead; with a build step it is set in the SFC build plugin.
A Vue 3 parent renders three child components and changes a prop passed to only one of them; which components re-render, and why?
basics
~20 sThe parent re-renders because its render read the changed state. The child whose prop changed re-renders. The two siblings are reached by the patch but skipped, because their props compare equal, so their render functions and descendants do not run.
In Vue 3, how does the runtime-only build differ from the full build, and why do most apps ship the runtime-only one?
basics
~20 sThe full build includes Vue's template compiler, so it can compile template strings in the browser; the runtime-only build does not. Apps with a build step precompile templates into render functions, so shipping the compiler would be wasted bytes and work.
In Vue 3, what runtime hints does a compiled template give the renderer that a hand-written h() render function does not?
basics
~20 sA compiled template adds patch flags, cached static vnodes and blocks with a flat list of dynamic descendants, so updates touch only what can change. h() output has none of these, so Vue fully diffs its props and children on each update.
In Vue 3, what arguments does h() take, and how does a Composition API component return a render function instead of a template?
basics
~20 sh(type, props?, children?) creates a vnode from a tag string or component, flat props with onXxx listeners, and children. setup() returns a function, not a vnode; that function re-runs on every render while setup runs once.
In Vue 3, what is a vnode, and what is the difference between the renderer mounting it and patching it?
basics
~20 sA vnode is a plain JavaScript object describing a piece of UI: its type, props, children and key. Mounting creates real DOM from a new vnode tree; patching compares the new tree with the previous one and changes only what differs.
In Vue 3, why is rendering a v-for list of 10,000 rows slow, and how does list virtualization fix it?
basics
~20 sEvery rendered row costs DOM nodes, vnodes and often a component instance, so 10,000 rows are slow to mount and patch in any framework. Virtualization renders only rows near the viewport, keeping that cost roughly constant.
In Vue 3, how do you keep a heavy component out of the initial bundle, and what can silently undo the split?
basics
~10 sWrap a dynamic import in defineAsyncComponent, e.g. defineAsyncComponent(() => import('./Chart.vue')), and render it only when needed. A static import of the same file elsewhere, or rendering it on first paint, undoes the gain.
In Vue 3, when a parent component re-renders, what decides whether each child component re-renders as well?
basics
~20 sA Vue child re-renders only if its own tracked state changed or the parent hands it changed props or dynamic slots. Props are compared per key by identity, so primitives stay stable while fresh objects, arrays or functions count as changed.
When a Vue 3 app feels slow, what can the official Vue devtools extension show you, and why won't it attach to a default production build?
basics
~20 sThe Vue devtools extension shows the component tree, each component's props and state, a timeline of events, and per-component render and patch timings in development builds. Production builds compile devtools support out unless VUE_PROD_DEVTOOLS is true.
In a Vue 3 template, what does the v-once directive do, and when is it the right tool?
basics
~20 sv-once renders an element, component or subtree once with the current data, then treats it as static content that every later re-render skips. Use it for content that reads data but never needs to update.
In a Vue 3 SSR app, what is the difference between createSSRApp and createApp, and which one must the browser entry call?
basics
~20 screateSSRApp creates an app whose mount() hydrates the server-rendered DOM in the container; createApp's mount() clears the container and renders from scratch. The browser entry of an SSR app must use createSSRApp, usually through the shared app factory.
A Vue 3 `<script setup>` component reads localStorage at the top of setup and the server render crashes. Why, and how do you fix it?
basics
~20 sSetup code, including the whole root scope of script setup, runs on the server, where there is no visitor's localStorage. Start from a server-safe default and read localStorage inside onMounted, which Vue never calls during SSR.
A Vue 3 SSR component renders `new Date().toLocaleTimeString()` and hydration warns about a text mismatch; why, and how would you fix it?
basics
~20 sThe component renders once on the server and again in the browser, at a different instant and often in a different time zone and locale, so the text differs. Render a stable placeholder and set the time in onMounted, or make the value deterministic.
When hand-rolling Vue 3 SSR on a small Node server, how do you split the code into universal, server and client entries?
basics
~20 sA universal module exports a factory that calls createSSRApp. The server entry calls it per request, renders with renderToString and wraps the HTML in a page shell with state and the client script. The client entry calls it once, restores state and mounts.
In a Vue 3 SSR app, a store created with reactive() at module scope shows one visitor's data to another visitor. Why, and what is Vue's recommended fix?
basics
~20 sOn the server a module is evaluated once per process, so a module-level reactive() object is shared by every request. Vue's fix: create a new app per request, create the store inside that factory, and share it with app.provide.
In Vue 3 with TypeScript, why do you wrap a component in defineComponent() when you are not using `<script setup>`?
basics
~20 sdefineComponent is a type helper: it returns the options object unchanged at runtime but lets TypeScript infer props, data and computed types on this and in setup(props). Its 3.3+ function form also supports generic render-function components.
In a Vue 3.5 `<script setup lang="ts">` component, how do you declare props with a TypeScript type, and what does the compiler generate from it?
basics
~20 sPass a type argument to defineProps, for example defineProps<{ options: Option[]; selected?: string }>(). The SFC compiler reads that type and generates the runtime props declaration: non-optional props become required, and constructors such as Array and String are inferred.
In Vue 3 with TypeScript, how do you type a ref that may hold `string | number`, and what does `ref<number>()` without an argument produce?
basics
~20 sPass a type argument, ref<string | number>('2020'), or annotate the variable as Ref<string | number>. Without either, the type is inferred from the initial value only. ref<number>() with no argument is typed Ref<number | undefined>.
In a Vite-based Vue 3 TypeScript project, why can the dev server and production build succeed despite type errors, and what catches them?
basics
~20 sVue's Vite-based setup is transpilation-only: the dev server and bundler strip types from each file without type-checking, to stay fast. Type errors are caught by the editor's Vue language tools and by running vue-tsc --noEmit in a script or CI.
In Vue 3.5, how do `withDefaults` and destructured defaults differ for type-based props such as a SelectInput's `options?: Option[]`?
basics
~20 swithDefaults(defineProps<Props>(), { options: () => [] }) needs factory functions for mutable defaults. Since 3.5, destructuring, const { options = [] } = defineProps<Props>(), lets the compiler add the factory. Both compile to runtime defaults.
What do Vue Test Utils' `trigger()` and `setValue()` return, and why must a test await them before checking the DOM?
basics
~10 sBoth return a promise from Vue's nextTick. Dispatching the event updates state synchronously, but Vue applies the resulting DOM patch asynchronously, so a test that does not await reads the old DOM.
When testing a Vue 3 composable, when can the test simply call it, and when does it need a host component?
basics
~20 sA composable that only uses reactivity APIs such as ref, computed and watch can be called directly in a test. One that registers lifecycle hooks like onMounted, or calls inject, needs a component instance, so it must run inside a host component's setup.
With Vue Test Utils, how do you mount a component that calls `inject('theme')` and renders `$t('title')` without installing the real i18n plugin?
basics
~20 sPass both under mount's global option: global.provide with a theme key fills the app-level provides that inject('theme') reads, and global.mocks with a fake $t puts that property on the component instance so the template's $t call resolves.
With Vue Test Utils' mount(), how do you pass props, slots and attrs to a Vue component, and change its props later?
basics
~20 sPass an options object as mount()'s second argument: props for declared props, slots keyed by slot name (a string, an h() vnode or a component) and attrs for undeclared attributes. Change props later with await wrapper.setProps({...}) on the root wrapper.
With Vue Test Utils, why is awaiting `trigger('submit')` not enough to see a form's success message after an API call, and what does `flushPromises()` add?
basics
~20 sAwaiting trigger only waits for Vue's pending DOM update, not for the request promise the submit handler awaits. flushPromises() resolves on the next macrotask, so already-settled mock promises, their continuations and Vue's re-render all run first.
Upgrading a Vue 2 entry file that uses `Vue.use`, `Vue.component` and `Vue.prototype.$http`, what replaces each in Vue 3, and why?
basics
~20 sVue 3 moves the APIs that globally mutated Vue onto the app returned by createApp: app.use, app.component, app.directive, app.mixin, and app.config.globalProperties for Vue.prototype. Vue 2's shared global config leaked plugins and settings across apps and tests.
When upgrading a Vue 2 component used with `v-model` and `:title.sync`, what must change in the child and in the parent for Vue 3?
basics
~10 sVue 3's component v-model uses the modelValue prop and update:modelValue event instead of value and input. The model option and .sync are removed: parents write v-model:title, which binds title and listens for update:title.
In Vue 2, why did `this.user.nickname = 'Ace'`, a key missing from `data`, not update the view, and how did `Vue.set` fix it?
basics
~20 sVue 2 turned each property that existed at creation into an Object.defineProperty getter/setter. A key added later is a plain property with no setter, so the write goes unseen; Vue.set(obj, key, value), or this.$set, adds it reactively and notifies watchers.
Vue 3 removed filters like `{{ price | currency }}`; what replaces a local filter and a globally registered one?
basics
~20 sVue 3 dropped filters, so a local filter becomes a method call or computed property and a global Vue.filter becomes a function you import, or one exposed as app.config.globalProperties.$filters. The pipe in a template is now JavaScript's bitwise OR.
In Vue 2, why did `this.items[2] = 'x'` and `this.items.length = 0` leave the view stale, and what did you write instead?
basics
~20 sVue 2 saw array changes only through its wrapped mutation methods: push, pop, shift, unshift, splice, sort and reverse. Index assignment and length writes bypass them. Use splice(2, 1, 'x') or this.$set(items, 2, 'x'), and splice(0) or a new array to empty it.