Writing
Blog
Notes on engineering, design, and what I'm learning while building.
Writing
Notes on engineering, design, and what I'm learning while building.
Article
I authored vue/v-if-else-key, now merged into eslint-plugin-vue — a rule that catches a subtle Vue 2 virtual-DOM bug where conditionally rendered, repeated components reuse the wrong instance. Here's the problem it solves and how it works.
I am beyond excited to share that a new ESLint rule I developed for Vue.js has been officially approved and merged into eslint-plugin-vue — the official linting plugin for Vue. Working with this library is part of my daily routine, so it is incredibly fulfilling to now be the author of one of its rules. It marks a real milestone in my coding journey. 🌟
The rule is vue/v-if-else-key, and it shipped in eslint-plugin-vue v9.19.0. Here's the bug it catches and why it matters.
→ See the rule: official documentation · source on GitHub
Vue renders efficiently by diffing a virtual DOM and reusing existing component instances wherever it can, instead of tearing down and rebuilding the real DOM. That reuse is usually exactly what you want — it's why Vue is fast.
But it has a sharp edge. When you render the same component across the branches of a v-if / v-else-if / v-else chain, Vue 2's diffing algorithm sees the same component type in the same position and happily reuses the existing instance when the condition flips — carrying its internal state, input values, and DOM along with it.
Consider this:
<template>
<my-component v-if="condition1" />
<my-component v-else-if="condition2" />
<my-component v-else />
</template>These look like three distinct branches, but to the diffing algorithm they're the same my-component in the same slot. Flip from condition1 to condition2 and Vue patches the existing instance in place rather than creating a fresh one. The result is state bleeding across branches that were supposed to be independent — a stale form value, a leftover scroll position, a component that never re-ran its setup logic. It's the kind of bug that's maddening to track down because the template looks correct.
The Vue 2 style guide explicitly warns against this pattern. The fix is to give each branch a unique key, which tells Vue "these are genuinely different — don't reuse one for the other":
<template>
<my-component v-if="condition1" :key="one" />
<my-component v-else-if="condition2" :key="two" />
<my-component v-else :key="three" />
</template>Distinct keys force Vue to treat each branch as its own element: destroy the old instance, mount a fresh one, no state carried over.
vue/v-if-else-key automates that guidance. It identifies components that are both repeated and conditionally rendered within the same scope, checks for the presence of a key directive, and reports a warning when it's missing.
The rule's one-line description says it plainly:
require key attribute for conditionally rendered repeated components
And it's auto-fixable — run ESLint with --fix and it can add the missing keys for you, so an entire codebase can be brought into line in one pass.
This rule is not needed in Vue 3. Vue 3 assigns keys to these elements automatically, so the instance-reuse footgun is closed at the framework level. The rule exists to protect Vue 2 codebases, where the responsibility still sits with the author.
If you've used vue/require-v-for-key — the rule that enforces a key on v-for — this is its conditional-rendering sibling. Same underlying concern (give the virtual DOM the identity hints it needs), different trigger.
A good lint rule encodes a hard-won lesson so the next engineer never has to learn it the painful way. This one takes a subtle, intermittent, state-corruption bug — the kind that survives code review because the template reads fine — and turns it into a deterministic warning with an automatic fix.
Contributing it back to a tool I rely on every day, and knowing it now quietly protects Vue 2 codebases I'll never see, is exactly the kind of leverage I love about open source.
If you want to read the rule or use it, it's in the official docs: vue/v-if-else-key.