Install
$ agentstack add skill-xobotyi-cc-foundry-vue ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Vue
Composition API is the default. `` is the default syntax. If you reach for Options API, you need a reason.
Vue 3 rewards explicit, composable code. Prefer ref() over reactive(), composables over mixins, and typed props over runtime-only validation. References contain extended examples, rationale, and edge cases for each topic.
References
- Reactivity — [
${CLAUDE_SKILL_DIR}/references/reactivity.md]: Ref unwrapping, watchers, computed edge cases - SFC — [
${CLAUDE_SKILL_DIR}/references/sfc.md]: Full compiler macros catalog, scoped styles, template refs - Components — [
${CLAUDE_SKILL_DIR}/references/components.md]: Props, emits, slots, provide/inject - Composables — [
${CLAUDE_SKILL_DIR}/references/composables.md]: Design patterns, composition, restrictions - TypeScript — [
${CLAUDE_SKILL_DIR}/references/typescript.md]: Full utility types table, generic components, event
typing
- Performance — [
${CLAUDE_SKILL_DIR}/references/performance.md]: Update optimization, large lists, profiling
Reactivity
Choosing a Reactive Primitive
ref()— Default choice. Works with any value type.reactive()— Grouping related state when destructure is not needed.shallowRef()— Large immutable structures, external state integration.shallowReactive()— Root-level-only reactivity on objects.computed()— Derived state. Caches until dependencies change.
ref() Is the Primary API
- Works with primitives (
string,number,boolean). - Can be destructured from composable returns without losing reactivity.
- Can be reassigned (
count.value = newValue). - Consistent
.valueaccess pattern everywhere in script. - Access
.valuein script, omit in template — templates auto-unwrap top-level refs.
reactive() Limitations
- Cannot hold primitives.
- Reassignment loses reactivity —
state = reactive({...})breaks tracking. - Destructuring primitives loses reactivity — use
toRefs()if you must destructure. - Do not use
reactive()as the primary primitive. Useref().
Ref Unwrapping Rules
- Top-level refs in templates are auto-unwrapped:
{{ count }}works. - Non-top-level refs in plain objects are NOT unwrapped:
{{ obj.id + 1 }}breaks ifobj.idis a ref. Destructure to
top level to fix.
- Refs nested inside
reactive()objects are unwrapped automatically. - Refs inside reactive arrays/collections are NOT unwrapped — need
.value.
Computed Properties
- Keep computed getters pure — no side effects.
- Split complex computed into smaller ones.
- Computed caches its value; only recalculates when dependencies change.
- Computed stability (3.4+): only triggers effects when the returned value actually changes. Avoid returning new objects
from computed — each new object is "different".
- Writable computed is rare — use sparingly. Requires
get/setform.
Watchers
watch() vs watchEffect():
| Use watch() when | Use watchEffect() when | | ------------------------- | ------------------------------- | | Need old and new values | Don't need old value | | Want lazy execution | Want immediate execution | | Watching specific sources | Dependencies are implicit | | Need conditional watching | Effect tracks all accessed refs |
watch() options:
{ immediate: true }— run callback on creation (like watchEffect).{ deep: true }— watch all nested properties (expensive, use sparingly).- Watch a getter for specific property:
watch(() => obj.specificProp, callback). - Watch multiple sources:
watch([a, b], ([newA, newB]) => {...}).
Cleanup: Both watch and watchEffect support cleanup via the onCleanup parameter. Use it for aborting fetch requests, clearing timers, removing listeners.
DOM Update Timing
Reactive state changes batch DOM updates to the next tick. Use nextTick() for post-DOM-update logic.
Single-File Components
Block Order
Always: ` first, second, ` last.
Organization Within ``
Order declarations logically:
- Imports — Vue APIs, components, composables, types
- Props and emits —
defineProps,defineEmits - Composable calls —
useRouter(), custom composables - Reactive state —
ref(),reactive(),computed() - Functions — event handlers, helpers
- Watchers —
watch(),watchEffect() - Lifecycle hooks —
onMounted(),onUnmounted() - Expose —
defineExpose()(rare)
Compiler Macros
Key macros available without import in `: defineProps(), defineEmits(), defineModel(). Use defineOptions() for options that doesn't natively support (name, inheritAttrs: false). Full macro catalog in ${CLAUDESKILLDIR}/references/sfc.md`.
Template Syntax
Directive shorthands — use consistently, don't mix:
:prop(v-bind:prop) — Bind attribute/prop@event(v-on:event) — Listen to event#slot(v-slot:slot) — Named slot
Conditional rendering:
v-if/v-else-if/v-elsefor conditional blocks.v-showfor frequent toggles (CSSdisplay: none, avoids mount/unmount cost).- Use
v-iffor conditions that rarely change,v-showfor frequent toggles.
Template refs:
- 3.5+:
useTemplateRef('input')with matchingrefattribute. - Pre-3.5:
ref(null)with matching ref name.
Scoped Styles
- Use `
by default. Global styles only inApp.vue` or layouts. - Child component root elements are affected by both parent and child scoped styles.
- Deep selectors:
.parent :deep(.child-class)to style child internals (use sparingly). - CSS modules: `
generates unique class names, accessed via$style`. v-bind(color)in `` uses reactive values in CSS.
Components
Naming
- Multi-word names always —
TodoItemnotItem. Avoids HTML element conflicts. - PascalCase in SFC templates: ``. Kebab-case only in in-DOM templates.
- PascalCase filenames:
TodoItem.vue. - Base component prefix for presentational components:
BaseButton,BaseIcon. - Parent prefix for tightly coupled children:
TodoListItem,TodoListItemButton. - Highest-level word first to group related:
SearchButtonClear,SearchInputQuery. - Full words always — no abbreviations.
- One component per file. No inline registration.
- Self-closing tags for components without children: ``.
- PascalCase when importing in JS/TS.
Props
- Use
defineProps()(type-based) in TypeScript projects. Object syntax in JS projects. Never array syntax in
committed code.
- Declare in
camelCase, use in templates askebab-case— Vue converts automatically. - Never mutate props. Use
computed()for transformations,ref()+ initial value for local copies. - One-way data flow — props down, events up.
- Reactive props destructure (3.5+): destructured props are reactive, usable in watch/computed directly.
- Pass destructured props to composables via getter:
useComposable(() => id).
Emits
- Declare all emits with
defineEmits()— preferably type-based. - Emit in
camelCase:emit('someEvent'). Listen inkebab-case:@some-event="handler". Vue converts automatically. - Use named tuple syntax (3.3+) for type-based emits:
defineEmits().
v-model
- Use
defineModel()for two-way binding shorthand. - Named v-model:
defineModel('firstName')withv-model:first-name="first"on parent.
Slots
- Default slot: `` in child, content between tags in parent.
- Named slots: `
in child,` in parent. - Scoped slots: pass data via slot props — `
, consume with`.
Provide / Inject
- Use
Symbolkeys (InjectionKey) for type safety — avoid string collisions. - Export keys from a shared
keys.tsfile. - Provide
readonly()refs to prevent consumers from mutating state. - Provide updater functions when consumers need to change provided state.
- Always provide a default or handle
undefinedin the consumer.
Template Rules
v-foralways has:key— stable, unique identifiers.- Never
v-ifon same element asv-for. Usecomputedto filter, or wrap with ``. - Simple expressions only in templates. Move logic to
computedor functions. - Multi-attribute elements span multiple lines — one attribute per line.
Composables
Design
- Always prefix with
use:useMouse,useFetch,useAuth. camelCasenaming:useEventListenernotuse-event-listener.- The
useprefix signals the function uses Vue reactivity and must be called withinsetup()or ``.
Structure
Follow this order: (1) reactive state, (2) logic that modifies state, (3) lifecycle hooks for side effects, (4) return refs.
Return Values
Always return a plain object containing refs. Never return a reactive() object — it loses reactivity on destructure. If the consumer wants an object, they can wrap: const mouse = reactive(useMouse()).
Input Arguments
Accept refs, getters, and raw values. Use toValue() (with MaybeRefOrGetter type) to normalize inputs inside watchEffect so reactive sources are tracked.
Side Effects and Cleanup
- Always clean up side effects in
onUnmounted()— event listeners, timers, subscriptions. - SSR safety: DOM-specific effects go in
onMounted()/onUnmounted(), not at top level.
Composition
Composables can call other composables — build complex logic by composing simple hooks.
Usage Restrictions
- Must be called inside `
orsetup()` function. - Must be called synchronously — not inside async callbacks or promises.
- Exception: `
restores the active instance afterawait, so composables work afterawait` in
``.
- Inside lifecycle hooks like
onMounted()is acceptable.
Composables vs Alternatives
- Mixins — Unclear property sources, namespace collisions, implicit coupling
- Renderless components — Extra component instance overhead
- Utility functions — No reactive state or lifecycle hooks
TypeScript
Props
- Use
defineProps()with an interface. - Defaults with 3.5+ destructure:
const { title, count = 0 } = defineProps(). - Defaults with 3.4 and below:
withDefaults(defineProps(), { count: 0 }). Mutable reference defaults (arrays,
objects) must use factory functions with withDefaults.
- Imported types work since Vue 3.3.
Emits
Use named tuple syntax (3.3+): defineEmits().
Refs
- Refs infer types from initial values —
ref(0)isRef. - Use explicit type for union types:
ref('2024'). - Nullable:
ref(null). - Without initial value:
ref()yieldsRef.
Computed
Types are inferred. Use explicit generic only when inference falls short: computed(() => ...).
Reactive
Annotate with interface, do not use reactive() generic — the returned type handles ref unwrapping differently from the generic parameter.
Template Refs
- 3.5+:
useTemplateRef('input'). - Component refs:
useTemplateRef>('comp'). - Pre-3.5:
ref(null).
Provide / Inject
Use InjectionKey for type-safe keys. String keys require generic annotation: inject('key').
Generic Components
Use generic attribute on `: `.
Event Handlers
Type DOM events explicitly: (event: Event) then cast target: event.target as HTMLInputElement.
Utility Types
Use Vue's typed helpers: Ref, ComputedRef, MaybeRefOrGetter, InjectionKey, PropType, ComponentPublicInstance. Full utility types table in ${CLAUDE_SKILL_DIR}/references/typescript.md.
Performance
Page Load
- Use dynamic imports for route-level code splitting.
- Use
defineAsyncComponent()for component-level splitting. - Prefer tree-shakable dependencies (
lodash-esoverlodash). - `` compiles to more minification-friendly code than Options API.
Update Performance
- Props stability — pass derived booleans (
active="item.id === activeId") instead of raw IDs to prevent
unnecessary child re-renders.
v-once— render once, skip all future updates. For truly static content.v-memo— conditionally skip sub-tree updates. Accepts a dependency array; only re-renders when a dependency
changes. Use on v-for lists where most items don't change.
- Computed stability (3.4+) — computed only triggers effects when value actually changes. Avoid returning new
objects from computed (each new object is "different").
Large Lists
- Virtual scrolling for 1000+ items — render only visible items (
vue-virtual-scroller,vueuc/VVirtualList). shallowRef()for large immutable datasets — mutations must replace the whole value.- Avoid unnecessary wrapper components in large lists — every component instance has overhead.
Watch Performance
- Avoid
{ deep: true }on large objects — watch specific properties instead. - Throttle/debounce watchers for expensive callbacks (e.g.,
useDebounceFnfrom VueUse).
Profiling
- Enable
app.config.performance = truefor Vue-specific performance markers. - Use Chrome DevTools Performance panel and Vue DevTools profiler.
- Measure before and after — don't optimize without data.
Application
When writing Vue code:
- Apply all conventions silently — don't narrate each rule being followed.
- If an existing codebase contradicts a convention, follow the codebase and flag the divergence once.
- Always use `` unless there is a documented reason not to.
When reviewing Vue code:
- Cite the specific violation and show the fix inline.
- Don't lecture or quote the rule — state what's wrong and how to fix it.
Integration
This skill provides Vue-specific conventions. The coding skill governs workflow; language skills govern JS/TS choices; this skill governs component architecture, reactivity patterns, and framework API usage.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: xobotyi
- Source: xobotyi/cc-foundry
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.