Files
agent-skills/skills/vue-best-practices/reference/render-function-v-for-keys-required.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

3.8 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Always Include key Props When Rendering Lists in Render Functions HIGH Missing keys cause inefficient re-renders and state bugs in dynamic lists best-practice
vue3
render-function
v-for
performance
key

Always Include key Props When Rendering Lists in Render Functions

Impact: HIGH - Omitting key props when rendering lists with h() or JSX causes Vue to use an inefficient "in-place patch" strategy, leading to performance issues and state bugs when list items have internal state or are reordered.

When rendering lists in render functions using .map(), always include a unique key prop on each item. This is the render function equivalent of using :key with v-for in templates.

Task Checklist

  • Always provide a key prop when mapping over arrays in render functions
  • Use unique, stable identifiers (like id) for keys, not array indices
  • Ensure keys are primitive values (strings or numbers)
  • Never use the same key for different items in the same list

Incorrect:

import { h } from 'vue'

export default {
  setup() {
    const items = ref([
      { id: 1, name: 'Apple' },
      { id: 2, name: 'Banana' }
    ])

    return () => h('ul',
      // WRONG: No keys - causes inefficient patching
      items.value.map(item =>
        h('li', item.name)
      )
    )
  }
}
// WRONG: Using array index as key when list can be reordered
export default {
  setup() {
    const todos = ref([...])

    return () => (
      <ul>
        {todos.value.map((todo, index) => (
          <TodoItem
            key={index}  // Bad: index changes when list reorders
            todo={todo}
          />
        ))}
      </ul>
    )
  }
}

Correct:

import { h } from 'vue'

export default {
  setup() {
    const items = ref([
      { id: 1, name: 'Apple' },
      { id: 2, name: 'Banana' }
    ])

    return () => h('ul',
      // CORRECT: Unique id as key
      items.value.map(item =>
        h('li', { key: item.id }, item.name)
      )
    )
  }
}
// CORRECT: Using stable unique identifier as key
export default {
  setup() {
    const todos = ref([
      { id: 'a1', text: 'Learn Vue' },
      { id: 'b2', text: 'Build app' }
    ])

    return () => (
      <ul>
        {todos.value.map(todo => (
          <TodoItem
            key={todo.id}  // Good: stable unique identifier
            todo={todo}
          />
        ))}
      </ul>
    )
  }
}
import { h } from 'vue'

export default {
  setup() {
    const users = ref([])

    return () => h('div', [
      h('h2', 'User List'),
      h('ul',
        users.value.map(user =>
          h('li', { key: user.email }, [  // email is unique
            h('span', user.name),
            h('span', ` (${user.email})`)
          ])
        )
      )
    ])
  }
}

When Index Keys Are Acceptable

Using array indices as keys is acceptable ONLY when:

  1. The list is static and will never be reordered
  2. Items will never be inserted or removed from the middle
  3. Items have no internal component state
// Index is OK here: static list that never changes
const staticLabels = ['Name', 'Email', 'Phone']

return () => h('tr',
  staticLabels.map((label, index) =>
    h('th', { key: index }, label)
  )
)

Why Keys Matter

Without keys, Vue uses an "in-place patch" strategy:

  1. It reuses DOM elements in place
  2. Updates element content to match new data
  3. This breaks when components have internal state or transitions

With proper keys:

  1. Vue tracks each item's identity
  2. Elements are moved, created, or destroyed correctly
  3. Component state is preserved during reorders

Reference