Skills create-adaptable-composable
Create a library-grade Vue composable that accepts maybe-reactive inputs (MaybeRef / MaybeRefOrGetter) so callers can pass a plain value, ref, or getter. Normalize inputs with toValue()/toRef() inside reactive effects (watch/watchEffect) to keep behavior predictable and reactive. Use this skill when user asks for creating adaptable or reusable composables.
install
source · Clone the upstream repo
git clone https://github.com/vuejs-ai/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/vuejs-ai/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/create-adaptable-composable" ~/.claude/skills/vuejs-ai-skills-create-adaptable-composable && rm -rf "$T"
manifest:
skills/create-adaptable-composable/SKILL.mdsource content
Create Adaptable Composable
Adaptable composables are reusable functions that can accept both reactive and non-reactive inputs. This allows developers to use the composable in a variety of contexts without worrying about the reactivity of the inputs.
Steps to design an adaptable composable in Vue.js:
- Confirm the composable's purpose and API design and expected inputs/outputs.
- Identify inputs params that should be reactive (MaybeRef / MaybeRefOrGetter).
- Use
ortoValue()
to normalize inputs inside reactive effects.toRef() - Implement the core logic of the composable using Vue's reactivity APIs.
Core Type Concepts
Type Utilities
/** * value or writable ref (value/ref/shallowRef/writable computed) */ export type MaybeRef<T = any> = T | Ref<T> | ShallowRef<T> | WritableComputedRef<T>; /** * MaybeRef<T> + ComputedRef<T> + () => T */ export type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T);
Policy and Rules
- Read-only, computed-friendly input: use
MaybeRefOrGetter - Needs to be writable / two-way input: use
MaybeRef - Parameter might be a function value (callback/predicate/comparator): do not use
, or you may accidentally invoke it as a getter.MaybeRefOrGetter - DOM/Element targets: if you want computed/derived targets, use
.MaybeRefOrGetter
When
MaybeRefOrGetter or MaybeRef is used:
- resolve reactive value using
(e.g. watcher source)toRef() - resolve non-reactive value using
toValue()
Examples
Adaptable
useDocumentTitle Composable: read-only title parameter
import { watch, toRef } from 'vue' import type { MaybeRefOrGetter } from 'vue' export function useDocumentTitle(title: MaybeRefOrGetter<string>) { watch(toRef(title), (t) => { document.title = t }, { immediate: true }) }
Adaptable
useCounter Composable: two-way writable count parameter
import { watch, toRef } from 'vue' import type { MaybeRef } from 'vue' function useCounter(count: MaybeRef<number>) { const countRef = toRef(count) function add() { countRef.value++ } return { add } }