@dianzhong/create-harness-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/index.mjs +412 -0
  2. package/package.json +29 -0
  3. package/templates/axios/.env.example +2 -0
  4. package/templates/axios/src/api/auth.ts +19 -0
  5. package/templates/axios/src/api/request.ts +61 -0
  6. package/templates/axios/src/types/api.ts +26 -0
  7. package/templates/axios/src/utils/auth.ts +5 -0
  8. package/templates/axios/src/utils/storage.ts +17 -0
  9. package/templates/harness/full/.agents/skills/find-skills/SKILL.md +143 -0
  10. package/templates/harness/full/.agents/skills/vue-best-practices/LICENSE.md +21 -0
  11. package/templates/harness/full/.agents/skills/vue-best-practices/SKILL.md +155 -0
  12. package/templates/harness/full/.agents/skills/vue-best-practices/SYNC.md +5 -0
  13. package/templates/harness/full/.agents/skills/vue-best-practices/references/animation-class-based-technique.md +258 -0
  14. package/templates/harness/full/.agents/skills/vue-best-practices/references/animation-state-driven-technique.md +287 -0
  15. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-async.md +99 -0
  16. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-data-flow.md +313 -0
  17. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-fallthrough-attrs.md +179 -0
  18. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-keep-alive.md +139 -0
  19. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-slots.md +226 -0
  20. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-suspense.md +231 -0
  21. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-teleport.md +110 -0
  22. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-transition-group.md +131 -0
  23. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-transition.md +135 -0
  24. package/templates/harness/full/.agents/skills/vue-best-practices/references/composables.md +303 -0
  25. package/templates/harness/full/.agents/skills/vue-best-practices/references/directives.md +168 -0
  26. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +177 -0
  27. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +185 -0
  28. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-virtualize-large-lists.md +182 -0
  29. package/templates/harness/full/.agents/skills/vue-best-practices/references/plugins.md +178 -0
  30. package/templates/harness/full/.agents/skills/vue-best-practices/references/reactivity.md +371 -0
  31. package/templates/harness/full/.agents/skills/vue-best-practices/references/render-functions.md +227 -0
  32. package/templates/harness/full/.agents/skills/vue-best-practices/references/sfc.md +355 -0
  33. package/templates/harness/full/.agents/skills/vue-best-practices/references/state-management.md +138 -0
  34. package/templates/harness/full/.agents/skills/vue-best-practices/references/updated-hook-performance.md +193 -0
  35. package/templates/harness/full/.claude/agents/code-reviewer.md +109 -0
  36. package/templates/harness/full/.claude/agents/harness-reviewer.md +51 -0
  37. package/templates/harness/full/.claude/hooks/guard-tool.cjs +234 -0
  38. package/templates/harness/full/.claude/hooks/notify.cjs +168 -0
  39. package/templates/harness/full/.claude/hooks/quality-gate.cjs +135 -0
  40. package/templates/harness/full/.claude/rules/delivery.md +66 -0
  41. package/templates/harness/full/.claude/rules/formatting.md +7 -0
  42. package/templates/harness/full/.claude/rules/git.md +8 -0
  43. package/templates/harness/full/.claude/rules/skills-mcp.md +13 -0
  44. package/templates/harness/full/.claude/rules/vue.md +227 -0
  45. package/templates/harness/full/.claude/settings.json +123 -0
  46. package/templates/harness/full/.claude/skills/find-skills/SKILL.md +143 -0
  47. package/templates/harness/full/.claude/skills/vue-best-practices/LICENSE.md +21 -0
  48. package/templates/harness/full/.claude/skills/vue-best-practices/SKILL.md +155 -0
  49. package/templates/harness/full/.claude/skills/vue-best-practices/SYNC.md +5 -0
  50. package/templates/harness/full/.claude/skills/vue-best-practices/references/animation-class-based-technique.md +258 -0
  51. package/templates/harness/full/.claude/skills/vue-best-practices/references/animation-state-driven-technique.md +287 -0
  52. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-async.md +99 -0
  53. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-data-flow.md +313 -0
  54. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-fallthrough-attrs.md +179 -0
  55. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-keep-alive.md +139 -0
  56. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-slots.md +226 -0
  57. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-suspense.md +231 -0
  58. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-teleport.md +110 -0
  59. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-transition-group.md +131 -0
  60. package/templates/harness/full/.claude/skills/vue-best-practices/references/component-transition.md +135 -0
  61. package/templates/harness/full/.claude/skills/vue-best-practices/references/composables.md +303 -0
  62. package/templates/harness/full/.claude/skills/vue-best-practices/references/directives.md +168 -0
  63. package/templates/harness/full/.claude/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +177 -0
  64. package/templates/harness/full/.claude/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +185 -0
  65. package/templates/harness/full/.claude/skills/vue-best-practices/references/perf-virtualize-large-lists.md +182 -0
  66. package/templates/harness/full/.claude/skills/vue-best-practices/references/plugins.md +178 -0
  67. package/templates/harness/full/.claude/skills/vue-best-practices/references/reactivity.md +371 -0
  68. package/templates/harness/full/.claude/skills/vue-best-practices/references/render-functions.md +227 -0
  69. package/templates/harness/full/.claude/skills/vue-best-practices/references/sfc.md +355 -0
  70. package/templates/harness/full/.claude/skills/vue-best-practices/references/state-management.md +138 -0
  71. package/templates/harness/full/.claude/skills/vue-best-practices/references/updated-hook-performance.md +193 -0
  72. package/templates/harness/full/.editorconfig +8 -0
  73. package/templates/harness/full/.husky/commit-msg +1 -0
  74. package/templates/harness/full/.husky/pre-commit +1 -0
  75. package/templates/harness/full/.lintstagedrc.json +4 -0
  76. package/templates/harness/full/.nvmrc +1 -0
  77. package/templates/harness/full/.oxlintrc.json +11 -0
  78. package/templates/harness/full/.prettierrc.json +6 -0
  79. package/templates/harness/full/AGENTS.md +3 -0
  80. package/templates/harness/full/CLAUDE.md +28 -0
  81. package/templates/harness/full/GEMINI.md +3 -0
  82. package/templates/harness/full/commitlint.config.ts +3 -0
  83. package/templates/harness/full/docs/ai-harness.md +77 -0
  84. package/templates/harness/full/docs/delivery-template.md +66 -0
  85. package/templates/harness/full/docs/git.md +24 -0
  86. package/templates/harness/full/docs/harness-quick-reference.md +89 -0
  87. package/templates/harness/full/docs/review-checklist.md +49 -0
  88. package/templates/harness/full/scripts/harness-hooks.test.mjs +218 -0
  89. package/templates/harness/full/scripts/verify-skills.mjs +248 -0
  90. package/templates/harness/full/scripts/verify-skills.test.mjs +72 -0
  91. package/templates/harness/full/skills-lock.json +50 -0
  92. package/templates/harness/minimal/.claude/hooks/guard-tool.cjs +234 -0
  93. package/templates/harness/minimal/.claude/hooks/quality-gate.cjs +135 -0
  94. package/templates/harness/minimal/.claude/settings.json +27 -0
  95. package/templates/harness/minimal/CLAUDE.md +12 -0
@@ -0,0 +1,231 @@
1
+ ---
2
+ title: Suspense Component Best Practices
3
+ impact: MEDIUM
4
+ impactDescription: Suspense coordinates async dependencies with fallback UI; misconfiguration leads to missing loading states or confusing UX
5
+ type: best-practice
6
+ tags:
7
+ [vue3, suspense, async-components, async-setup, loading, fallback, router, transition, keepalive]
8
+ ---
9
+
10
+ # Suspense Component Best Practices
11
+
12
+ **Impact: MEDIUM** - `<Suspense>` coordinates async dependencies (async components or async setup) and renders a fallback while they resolve. Misconfiguration leads to missing loading states, empty renders, or subtle UX bugs.
13
+
14
+ ## Task List
15
+
16
+ - Wrap default and fallback slot content in a single root node
17
+ - Use `timeout` when you need the fallback to appear on reverts
18
+ - Force root replacement with `:key` when you need Suspense to re-trigger
19
+ - Add `suspensible` to nested Suspense boundaries (Vue 3.3+)
20
+ - Use `@pending`, `@resolve`, and `@fallback` for programmatic loading state
21
+ - Nest `RouterView` -> `Transition` -> `KeepAlive` -> `Suspense` in that order
22
+ - Keep Suspense usage centralized and documented in production
23
+
24
+ ## Single Root in Default and Fallback Slots
25
+
26
+ Suspense tracks a single immediate child in both slots. Wrap multiple elements in a single element or component.
27
+
28
+ **BAD:**
29
+
30
+ ```vue
31
+ <template>
32
+ <Suspense>
33
+ <AsyncHeader />
34
+ <AsyncList />
35
+
36
+ <template #fallback>
37
+ <LoadingSpinner />
38
+ <LoadingHint />
39
+ </template>
40
+ </Suspense>
41
+ </template>
42
+ ```
43
+
44
+ **GOOD:**
45
+
46
+ ```vue
47
+ <template>
48
+ <Suspense>
49
+ <div>
50
+ <AsyncHeader />
51
+ <AsyncList />
52
+ </div>
53
+
54
+ <template #fallback>
55
+ <div>
56
+ <LoadingSpinner />
57
+ <LoadingHint />
58
+ </div>
59
+ </template>
60
+ </Suspense>
61
+ </template>
62
+ ```
63
+
64
+ ## Fallback Timing on Reverts (`timeout`)
65
+
66
+ When Suspense is already resolved and new async work starts, the previous content remains visible until the timeout elapses. Use `timeout="0"` for immediate fallback or a short delay to avoid flicker.
67
+
68
+ **BAD:**
69
+
70
+ ```vue
71
+ <template>
72
+ <Suspense>
73
+ <component :is="currentView" :key="viewKey" />
74
+
75
+ <template #fallback> Loading... </template>
76
+ </Suspense>
77
+ </template>
78
+ ```
79
+
80
+ **GOOD:**
81
+
82
+ ```vue
83
+ <template>
84
+ <Suspense :timeout="200">
85
+ <component :is="currentView" :key="viewKey" />
86
+
87
+ <template #fallback> Loading... </template>
88
+ </Suspense>
89
+ </template>
90
+ ```
91
+
92
+ ## Pending State Only Re-triggers on Root Replacement
93
+
94
+ Once resolved, Suspense only re-enters pending when the root node of the default slot changes. If async work happens deeper in the tree, no fallback appears.
95
+
96
+ **BAD:**
97
+
98
+ ```vue
99
+ <template>
100
+ <Suspense>
101
+ <TabContainer>
102
+ <AsyncDashboard v-if="tab === 'dashboard'" />
103
+ <AsyncSettings v-else />
104
+ </TabContainer>
105
+
106
+ <template #fallback> Loading... </template>
107
+ </Suspense>
108
+ </template>
109
+ ```
110
+
111
+ **GOOD:**
112
+
113
+ ```vue
114
+ <template>
115
+ <Suspense>
116
+ <component :is="tabs[tab]" :key="tab" />
117
+
118
+ <template #fallback> Loading... </template>
119
+ </Suspense>
120
+ </template>
121
+ ```
122
+
123
+ ## Use `suspensible` for Nested Suspense (Vue 3.3+)
124
+
125
+ Nested Suspense boundaries need `suspensible` on the inner boundary so the parent can coordinate loading state. Without it, inner async content may render empty nodes until resolved.
126
+
127
+ **BAD:**
128
+
129
+ ```vue
130
+ <template>
131
+ <Suspense>
132
+ <LayoutShell>
133
+ <Suspense>
134
+ <AsyncWidget />
135
+ <template #fallback> Loading widget... </template>
136
+ </Suspense>
137
+ </LayoutShell>
138
+
139
+ <template #fallback> Loading layout... </template>
140
+ </Suspense>
141
+ </template>
142
+ ```
143
+
144
+ **GOOD:**
145
+
146
+ ```vue
147
+ <template>
148
+ <Suspense>
149
+ <LayoutShell>
150
+ <Suspense suspensible>
151
+ <AsyncWidget />
152
+ <template #fallback> Loading widget... </template>
153
+ </Suspense>
154
+ </LayoutShell>
155
+
156
+ <template #fallback> Loading layout... </template>
157
+ </Suspense>
158
+ </template>
159
+ ```
160
+
161
+ ## Track Loading with Suspense Events
162
+
163
+ Use `@pending`, `@resolve`, and `@fallback` for analytics, global loading indicators, or coordinating UI outside the Suspense boundary.
164
+
165
+ ```vue
166
+ <script setup>
167
+ import { ref } from 'vue'
168
+
169
+ const isLoading = ref(false)
170
+
171
+ function onPending() {
172
+ isLoading.value = true
173
+ }
174
+
175
+ function onResolve() {
176
+ isLoading.value = false
177
+ }
178
+ </script>
179
+
180
+ <template>
181
+ <LoadingBar v-if="isLoading" />
182
+
183
+ <Suspense @pending="onPending" @resolve="onResolve">
184
+ <AsyncPage />
185
+ <template #fallback>
186
+ <PageSkeleton />
187
+ </template>
188
+ </Suspense>
189
+ </template>
190
+ ```
191
+
192
+ ## Recommended Nesting with RouterView, Transition, KeepAlive
193
+
194
+ When combining these components, the nesting order should be `RouterView` -> `Transition` -> `KeepAlive` -> `Suspense` so each wrapper works correctly.
195
+
196
+ **BAD:**
197
+
198
+ ```vue
199
+ <template>
200
+ <RouterView v-slot="{ Component }">
201
+ <Suspense>
202
+ <KeepAlive>
203
+ <Transition mode="out-in">
204
+ <component :is="Component" />
205
+ </Transition>
206
+ </KeepAlive>
207
+ </Suspense>
208
+ </RouterView>
209
+ </template>
210
+ ```
211
+
212
+ **GOOD:**
213
+
214
+ ```vue
215
+ <template>
216
+ <RouterView v-slot="{ Component }">
217
+ <Transition mode="out-in">
218
+ <KeepAlive>
219
+ <Suspense>
220
+ <component :is="Component" />
221
+ <template #fallback> Loading... </template>
222
+ </Suspense>
223
+ </KeepAlive>
224
+ </Transition>
225
+ </RouterView>
226
+ </template>
227
+ ```
228
+
229
+ ## Treat Suspense Cautiously in Production
230
+
231
+ In production code, keep Suspense boundaries minimal, document where they are used, and have a fallback loading strategy if you ever need to replace or refactor them.
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: Teleport Component Best Practices
3
+ impact: MEDIUM
4
+ impactDescription: Teleport renders content outside the component's DOM position, which is essential for overlays but affects styling and layout
5
+ type: best-practice
6
+ tags: [vue3, teleport, modal, overlay, positioning, responsive]
7
+ ---
8
+
9
+ # Teleport Component Best Practices
10
+
11
+ **Impact: MEDIUM** - `<Teleport>` renders part of a component's template in a different place in the DOM while preserving the Vue component hierarchy. Use it for overlays (modals, toasts, tooltips) or any UI that must escape stacking contexts, overflow, or fixed positioning constraints.
12
+
13
+ ## Task List
14
+
15
+ - Teleport overlays to `body` or a dedicated container outside the app root
16
+ - Keep a shared target for similar UI (`#modals`, `#notifications`) and control layering with order or z-index
17
+ - Use `:disabled` for responsive layouts that should render inline on small screens
18
+ - Remember props, emits, and provide/inject still work through teleport
19
+ - Avoid relying on parent stacking contexts or transforms for teleported UI
20
+
21
+ ## Teleport Overlays Out of Transformed Containers
22
+
23
+ When an ancestor has `transform`, `filter`, or `perspective`, fixed-position overlays can behave like they are locally positioned. Teleport escapes that context.
24
+
25
+ **BAD:**
26
+
27
+ ```vue
28
+ <template>
29
+ <div class="animated-container">
30
+ <button @click="open = true">Open</button>
31
+
32
+ <!-- Broken: fixed positioning is scoped to the transformed parent -->
33
+ <div v-if="open" class="modal">Modal</div>
34
+ </div>
35
+ </template>
36
+
37
+ <style>
38
+ .animated-container {
39
+ transform: translateZ(0);
40
+ }
41
+
42
+ .modal {
43
+ position: fixed;
44
+ inset: 0;
45
+ z-index: 9999;
46
+ }
47
+ </style>
48
+ ```
49
+
50
+ **GOOD:**
51
+
52
+ ```vue
53
+ <template>
54
+ <div class="animated-container">
55
+ <button @click="open = true">Open</button>
56
+
57
+ <Teleport to="body">
58
+ <div v-if="open" class="modal">Modal</div>
59
+ </Teleport>
60
+ </div>
61
+ </template>
62
+ ```
63
+
64
+ ## Responsive Layouts with `disabled`
65
+
66
+ Use `:disabled` to render inline on mobile and teleport on larger screens:
67
+
68
+ ```vue
69
+ <script setup>
70
+ import { useMediaQuery } from '@vueuse/core'
71
+
72
+ const isMobile = useMediaQuery('(max-width: 768px)')
73
+ </script>
74
+
75
+ <template>
76
+ <Teleport to="body" :disabled="isMobile">
77
+ <nav class="sidebar">Navigation</nav>
78
+ </Teleport>
79
+ </template>
80
+ ```
81
+
82
+ ## Logical Hierarchy Is Preserved
83
+
84
+ Teleport changes DOM position, not the Vue component tree. Props, emits, slots, and provide/inject still work:
85
+
86
+ ```vue
87
+ <template>
88
+ <Teleport to="body">
89
+ <ChildPanel :message="message" @close="open = false" />
90
+ </Teleport>
91
+ </template>
92
+ ```
93
+
94
+ ## Multiple Teleports to the Same Target
95
+
96
+ Teleports to the same target append in declaration order:
97
+
98
+ ```vue
99
+ <template>
100
+ <Teleport to="#notifications">
101
+ <div>First</div>
102
+ </Teleport>
103
+
104
+ <Teleport to="#notifications">
105
+ <div>Second</div>
106
+ </Teleport>
107
+ </template>
108
+ ```
109
+
110
+ Use a shared container to keep stacking predictable, and apply z-index only when you need explicit layering.
@@ -0,0 +1,131 @@
1
+ ---
2
+ title: TransitionGroup Component Best Practices
3
+ impact: MEDIUM
4
+ impactDescription: TransitionGroup animates list items; missing keys or misuse leads to broken list transitions
5
+ type: best-practice
6
+ tags: [vue3, transition-group, animation, lists, keys]
7
+ ---
8
+
9
+ # TransitionGroup Component Best Practices
10
+
11
+ **Impact: MEDIUM** - `<TransitionGroup>` animates lists of items entering, leaving, and moving. Use it for `v-for` lists or dynamic collections where individual items change over time.
12
+
13
+ ## Task List
14
+
15
+ - Use `<TransitionGroup>` only for lists and repeated items
16
+ - Provide unique, stable keys for every direct child
17
+ - Use `tag` when you need semantic or layout wrappers
18
+ - Avoid the `mode` prop (not supported)
19
+ - Use JavaScript hooks for staggered effects
20
+
21
+ ## Use TransitionGroup for Lists
22
+
23
+ `<TransitionGroup>` is designed for list items. Use `tag` to control the wrapper element when needed.
24
+
25
+ **BAD:**
26
+
27
+ ```vue
28
+ <template>
29
+ <TransitionGroup name="fade">
30
+ <ComponentA />
31
+ <ComponentB />
32
+ </TransitionGroup>
33
+ </template>
34
+ ```
35
+
36
+ **GOOD:**
37
+
38
+ ```vue
39
+ <template>
40
+ <TransitionGroup name="list" tag="ul">
41
+ <li v-for="item in items" :key="item.id">
42
+ {{ item.name }}
43
+ </li>
44
+ </TransitionGroup>
45
+ </template>
46
+ ```
47
+
48
+ ## Always Provide Stable Keys
49
+
50
+ Keys are required. Without stable keys, Vue cannot track item positions and animations break.
51
+
52
+ **BAD:**
53
+
54
+ ```vue
55
+ <template>
56
+ <TransitionGroup name="list" tag="ul">
57
+ <li v-for="(item, index) in items" :key="index">
58
+ {{ item.name }}
59
+ </li>
60
+ </TransitionGroup>
61
+ </template>
62
+ ```
63
+
64
+ **GOOD:**
65
+
66
+ ```vue
67
+ <template>
68
+ <TransitionGroup name="list" tag="ul">
69
+ <li v-for="item in items" :key="item.id">
70
+ {{ item.name }}
71
+ </li>
72
+ </TransitionGroup>
73
+ </template>
74
+ ```
75
+
76
+ ## Do Not Use `mode` on TransitionGroup
77
+
78
+ `mode` is only for `<Transition>` because it swaps a single element. Use `<Transition>` if you need in/out sequencing.
79
+
80
+ **BAD:**
81
+
82
+ ```vue
83
+ <template>
84
+ <TransitionGroup name="list" tag="div" mode="out-in">
85
+ <div v-for="item in items" :key="item.id">
86
+ {{ item.name }}
87
+ </div>
88
+ </TransitionGroup>
89
+ </template>
90
+ ```
91
+
92
+ **GOOD:**
93
+
94
+ ```vue
95
+ <template>
96
+ <Transition name="fade" mode="out-in">
97
+ <component :is="currentView" :key="currentView" />
98
+ </Transition>
99
+ </template>
100
+ ```
101
+
102
+ ## Stagger List Animations with Data Attributes
103
+
104
+ For cascading list animations, pass the index to JavaScript hooks and compute delay per item.
105
+
106
+ ```vue
107
+ <script setup>
108
+ function onBeforeEnter(el) {
109
+ el.style.opacity = 0
110
+ el.style.transform = 'translateY(12px)'
111
+ }
112
+
113
+ function onEnter(el, done) {
114
+ const delay = Number(el.dataset.index) * 80
115
+ setTimeout(() => {
116
+ el.style.transition = 'all 0.25s ease'
117
+ el.style.opacity = 1
118
+ el.style.transform = 'translateY(0)'
119
+ setTimeout(done, 250)
120
+ }, delay)
121
+ }
122
+ </script>
123
+
124
+ <template>
125
+ <TransitionGroup tag="ul" :css="false" @before-enter="onBeforeEnter" @enter="onEnter">
126
+ <li v-for="(item, index) in items" :key="item.id" :data-index="index">
127
+ {{ item.name }}
128
+ </li>
129
+ </TransitionGroup>
130
+ </template>
131
+ ```
@@ -0,0 +1,135 @@
1
+ ---
2
+ title: Transition Component Best Practices
3
+ impact: MEDIUM
4
+ impactDescription: Transition animates a single element or component; incorrect structure or keys prevent animations
5
+ type: best-practice
6
+ tags: [vue3, transition, animation, performance, keys]
7
+ ---
8
+
9
+ # Transition Component Best Practices
10
+
11
+ **Impact: MEDIUM** - `<Transition>` animates entering/leaving of a single element or component. It is ideal for toggling UI states, swapping views, or animating one component at a time.
12
+
13
+ ## Task List
14
+
15
+ - Wrap a single element or component inside `<Transition>`
16
+ - Provide a `key` when switching between same element types
17
+ - Use `mode="out-in"` when you need sequential swaps
18
+ - Prefer `transform` and `opacity` for smooth animations
19
+
20
+ ## Use Transition for a Single Root Element
21
+
22
+ `<Transition>` only supports one direct child. Wrap multiple nodes in a single element or component.
23
+
24
+ **BAD:**
25
+
26
+ ```vue
27
+ <template>
28
+ <Transition name="fade">
29
+ <h3>Title</h3>
30
+ <p>Description</p>
31
+ </Transition>
32
+ </template>
33
+ ```
34
+
35
+ **GOOD:**
36
+
37
+ ```vue
38
+ <template>
39
+ <Transition name="fade">
40
+ <div>
41
+ <h3>Title</h3>
42
+ <p>Description</p>
43
+ </div>
44
+ </Transition>
45
+ </template>
46
+ ```
47
+
48
+ ## Force Transitions Between Same Element Types
49
+
50
+ Vue reuses the same DOM element when the tag type does not change. Add `key` so Vue treats it as a new element and triggers enter/leave.
51
+
52
+ **BAD:**
53
+
54
+ ```vue
55
+ <template>
56
+ <Transition name="fade">
57
+ <p v-if="isActive">Active</p>
58
+ <p v-else>Inactive</p>
59
+ </Transition>
60
+ </template>
61
+ ```
62
+
63
+ **GOOD:**
64
+
65
+ ```vue
66
+ <template>
67
+ <Transition name="fade" mode="out-in">
68
+ <p v-if="isActive" key="active">Active</p>
69
+ <p v-else key="inactive">Inactive</p>
70
+ </Transition>
71
+ </template>
72
+ ```
73
+
74
+ ## Use `mode` to Avoid Overlap During Swaps
75
+
76
+ When swapping components or views, use `mode="out-in"` to prevent both from being visible at the same time.
77
+
78
+ **BAD:**
79
+
80
+ ```vue
81
+ <template>
82
+ <Transition name="fade">
83
+ <component :is="currentView" />
84
+ </Transition>
85
+ </template>
86
+ ```
87
+
88
+ **GOOD:**
89
+
90
+ ```vue
91
+ <template>
92
+ <Transition name="fade" mode="out-in">
93
+ <component :is="currentView" :key="currentView" />
94
+ </Transition>
95
+ </template>
96
+ ```
97
+
98
+ ## Animate `transform` and `opacity` for Performance
99
+
100
+ Avoid layout-triggering properties such as `height`, `margin`, or `top`. Use `transform` and `opacity` for smooth, GPU-friendly transitions.
101
+
102
+ **BAD:**
103
+
104
+ ```css
105
+ .slide-enter-active,
106
+ .slide-leave-active {
107
+ transition: height 0.3s ease;
108
+ }
109
+
110
+ .slide-enter-from,
111
+ .slide-leave-to {
112
+ height: 0;
113
+ }
114
+ ```
115
+
116
+ **GOOD:**
117
+
118
+ ```css
119
+ .slide-enter-active,
120
+ .slide-leave-active {
121
+ transition:
122
+ transform 0.3s ease,
123
+ opacity 0.3s ease;
124
+ }
125
+
126
+ .slide-enter-from {
127
+ transform: translateX(-12px);
128
+ opacity: 0;
129
+ }
130
+
131
+ .slide-leave-to {
132
+ transform: translateX(12px);
133
+ opacity: 0;
134
+ }
135
+ ```