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>
3.6 KiB
3.6 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | |||||
|---|---|---|---|---|---|---|---|---|---|
| Avoid Using Custom Directives on Components | HIGH | Custom directives on multi-root components are silently ignored, causing unexpected behavior | gotcha |
|
Avoid Using Custom Directives on Components
Impact: HIGH - Using custom directives on components is not recommended and can lead to unexpected behavior. When applied to a multi-root component, the directive will be ignored and a warning will be thrown. Unlike attributes, directives cannot be passed to a different element with v-bind="$attrs".
Custom directives are designed for direct DOM manipulation on native HTML elements, not Vue components.
Task Checklist
- Only apply custom directives to native HTML elements, not components
- If a component needs directive-like behavior, consider making it part of the component's API
- For components, use props and events instead of directives
- If you must use a directive on a component, ensure it has a single root element
Incorrect:
<template>
<!-- WRONG: Directive on a component - may be ignored -->
<MyComponent v-focus />
<!-- WRONG: Multi-root component - directive is ignored with warning -->
<MultiRootComponent v-highlight />
</template>
<script setup>
import MyComponent from './MyComponent.vue'
import MultiRootComponent from './MultiRootComponent.vue'
// MultiRootComponent.vue has:
// <template>
// <div>First root</div>
// <div>Second root</div>
// </template>
</script>
Correct:
<template>
<!-- CORRECT: Directive on native HTML element -->
<input v-focus />
<!-- CORRECT: Use props/events for component behavior -->
<MyComponent :should-focus="true" />
<!-- CORRECT: Wrap component in element if directive is needed -->
<div v-highlight>
<MyComponent />
</div>
</template>
<script setup>
import MyComponent from './MyComponent.vue'
</script>
When a Directive on Component Works
Directives only work reliably on components with a single root element. The directive applies to the root node, similar to fallthrough attributes:
<!-- SingleRootComponent.vue -->
<template>
<div>I am the only root</div>
</template>
<!-- Parent.vue -->
<template>
<!-- This works because SingleRootComponent has one root -->
<SingleRootComponent v-my-directive />
</template>
However, this is still not recommended because:
- It's fragile - refactoring to multi-root breaks the directive silently
- It's unclear which element receives the directive
- The component author may not expect external DOM manipulation
Better Patterns
Option 1: Component Prop
<!-- FocusableInput.vue -->
<template>
<input ref="inputRef" v-bind="$attrs" />
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
const props = defineProps({
autofocus: Boolean
})
const inputRef = ref(null)
onMounted(() => {
if (props.autofocus) {
inputRef.value?.focus()
}
})
</script>
<!-- Usage -->
<FocusableInput autofocus />
Option 2: Exposed Method
<!-- FocusableInput.vue -->
<template>
<input ref="inputRef" />
</template>
<script setup>
import { ref } from 'vue'
const inputRef = ref(null)
const focus = () => inputRef.value?.focus()
defineExpose({ focus })
</script>
<!-- Parent.vue -->
<template>
<FocusableInput ref="myInput" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
const myInput = ref(null)
onMounted(() => {
myInput.value?.focus()
})
</script>