
Create Adaptable Composable
Author Vue 3 composables that accept plain values, refs, or getters via MaybeRef/MaybeRefOrGetter so library consumers are not forced into one reactivity shape.
Overview
Create Adaptable Composable is an agent skill for the Build phase that guides library-grade Vue composables accepting MaybeRef and MaybeRefOrGetter inputs normalized with toValue() and toRef() inside reactive effects.
Install
npx skills add https://github.com/vuejs-ai/skills --skill create-adaptable-composableWhat is this skill?
- Four-step design flow: confirm API, mark reactive params, normalize with toValue/toRef, implement with Vue reactivity AP
- Documents MaybeRef vs MaybeRefOrGetter including writable computed and getter forms
- Library-grade pattern for predictable behavior when callers pass refs or plain values interchangeably
- Targets Vue 3+ and Nuxt 3+ per skill compatibility metadata version 17.0.0
- 4-step composable design checklist in SKILL.md
Adoption & trust: 6.8k installs on skills.sh; 2.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your composable only works with refs, so every caller wraps values manually and subtle reactivity bugs appear when inputs switch between getters and plain data.
Who is it for?
Vue or Nuxt developers extracting shared logic into npm-grade or monorepo composables used across components with mixed reactivity styles.
Skip if: One-off inline logic in a single component, non-Vue frameworks, or teams that do not need MaybeRef-style polymorphic inputs.
When should I use this skill?
User asks for creating adaptable or reusable Vue composables that accept MaybeRef / MaybeRefOrGetter inputs.
What do I get? / Deliverables
You get a documented composable API with correctly normalized reactive inputs and implementation aligned to Vue 3 reactivity primitives.
- Composable API spec with reactive parameter boundaries
- Implemented composable using toValue/toRef in watch or watchEffect
Recommended Skills
Journey fit
Composable design is core frontend implementation work while building Vue or Nuxt product UI and shared libraries. Frontend is where reusable composition API utilities live—normalizing inputs with toValue/toRef inside watch and watchEffect is a build-time pattern skill.
How it compares
Opinionated composable design recipe— not a component generator and not a Pinia store scaffold.
Common Questions / FAQ
Who is create-adaptable-composable for?
Solo frontend builders and maintainers of Vue 3 or Nuxt 3 codebases who want reusable composables that accept refs, values, or getters without breaking consumers.
When should I use create-adaptable-composable?
Use it in Build while designing or refactoring a shared composable whenever the user asks for adaptable, reusable, or library-grade composition API design with reactive parameter flexibility.
Is create-adaptable-composable safe to install?
It is documentation and coding guidance only with no exchange or production secrets; still review the Security Audits panel on this Prism page before adding any skill to your agent.
SKILL.md
READMESKILL.md - Create Adaptable Composable
# 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: 1. Confirm the composable's purpose and API design and expected inputs/outputs. 2. Identify inputs params that should be reactive (MaybeRef / MaybeRefOrGetter). 3. Use `toValue()` or `toRef()` to normalize inputs inside reactive effects. 4. Implement the core logic of the composable using Vue's reactivity APIs. ## Core Type Concepts ### Type Utilities ```ts /** * 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 `MaybeRefOrGetter`, or you may accidentally invoke it as a getter. - DOM/Element targets: if you want computed/derived targets, use `MaybeRefOrGetter`. When `MaybeRefOrGetter` or `MaybeRef` is used: - resolve reactive value using `toRef()` (e.g. watcher source) - resolve non-reactive value using `toValue()` ### Examples Adaptable `useDocumentTitle` Composable: read-only title parameter ```ts 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 ```ts 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 } } ```