create-adaptable-composable
vuejs-ai/skills
Create library-grade Vue composables that accept plain values, refs, or getters for maximum reusability.
What is create-adaptable-composable?
Build adaptable Vue 3 composables that normalize both reactive and non-reactive inputs using MaybeRef/MaybeRefOrGetter types. Use this skill when designing reusable composables that work seamlessly whether callers pass plain values, refs, computed properties, or getter functions.
- Accept flexible input types (plain values, refs, computed refs, or getter functions) via MaybeRef or MaybeRefOrGetter
- Normalize inputs using toValue() for non-reactive resolution and toRef() for reactive watchers
- Implement core logic with Vue's reactivity APIs (watch, watchEffect) while maintaining predictable behavior
- Design composables that work in any context without requiring callers to manage reactivity
- Support both read-only inputs (MaybeRefOrGetter) and writable two-way inputs (MaybeRef)
How to install create-adaptable-composable
npx skills add https://github.com/vuejs-ai/skills --skill create-adaptable-composable- Vue 3 or Nuxt 3 project
- Familiarity with Vue's reactivity system (ref, computed, watch)
- Understanding of TypeScript generics (recommended but not required)
How to use create-adaptable-composable
- 1.Identify which parameters should be reactive and choose MaybeRef (writable) or MaybeRefOrGetter (read-only)
- 2.Define your composable function signature with the appropriate type for each parameter
- 3.Inside watch/watchEffect, use toRef() to normalize inputs for reactive tracking
- 4.For non-reactive value access, use toValue() to unwrap the input
- 5.Test the composable with plain values, refs, computed properties, and getter functions to verify adaptability
Use cases
- Create a useDocumentTitle composable that updates the page title whether passed a string, ref, or computed property
- Build a useCounter composable that increments a count parameter whether it's a plain number or a ref
- Design a useApi composable that fetches data based on a URL that could be static, reactive, or computed
- Implement a useLocalStorage composable accepting a key that might be derived from other reactive state
- Create a useDebounce composable that works with any input type without forcing callers to wrap values in refs
- Vue 3 library authors building reusable composables
- Frontend developers creating component-agnostic utility functions
- Teams standardizing composable patterns across projects
- Developers building design systems or shared component libraries
create-adaptable-composable FAQ
Use MaybeRef when the input needs to be writable or two-way (e.g., a counter value). Use MaybeRefOrGetter for read-only inputs or when you want to support computed properties and getter functions (e.g., a title or URL).
toValue() unwraps the input and returns the current value (non-reactive). toRef() returns a ref object that tracks reactivity, making it suitable for watch sources and reactive effects.
No—if the parameter might be a callback, predicate, or comparator function, do not use MaybeRefOrGetter, as it will accidentally invoke the function as a getter. Use a separate parameter type instead.
Only for parameters you want to track reactively inside watch/watchEffect. For one-time reads or non-reactive access, use toValue() instead.
This skill requires Vue 3 or above, or Nuxt 3 or above. The MaybeRef and MaybeRefOrGetter types are built into Vue 3's core.
Full instructions (SKILL.md)
Source of truth, from vuejs-ai/skills.
name: create-adaptable-composable description: 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. license: MIT metadata: author: github.com/vuejs-ai version: "17.0.0" compatibility: Requires Vue 3 (or above) or Nuxt 3 (or above) project
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
toValue()ortoRef()to normalize inputs inside reactive effects. - 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
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
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 }
}
Related skills
More from vuejs-ai/skills and the wider catalog.

vue-best-practices
Vue 3 best practices guide: Composition API, TypeScript, and component architecture patterns.

vue-debug-guides
Vue 3 debugging guides for runtime errors, warnings, async failures, and hydration issues.

vue-development-guides
Best practices and patterns for Vue 3+ and Nuxt 3+ development with composition API and SFC guidelines.

vue-jsx-best-practices
Master Vue JSX syntax and avoid React JSX pitfalls in Vue components.

vue-options-api-best-practices
Vue 3 Options API best practices, TypeScript integration, and common gotchas reference.

vue-pinia-best-practices
Pinia store setup, state management patterns, and reactivity best practices for Vue.js