create-adaptable-composable
hyf0/vue-skills/skills/create-adaptable-composable/SKILL.md
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.
What's in it
- Create Adaptable Composable
- Core Type Concepts
- Type Utilities
- Policy and Rules
- Examples
---
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:
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 }
}
```
More agent context in hyf0/vue-skills
9 other files this repository gives its agents.
AGENTS.md
CLAUDE.md
Skill
- vue-best-practicesskills/vue-best-practices/SKILL.md
- vue-debug-guidesskills/vue-debug-guides/SKILL.md
- vue-jsx-best-practicesskills/vue-jsx-best-practices/SKILL.md
- vue-options-api-best-practicesskills/vue-options-api-best-practices/SKILL.md
- vue-pinia-best-practicesskills/vue-pinia-best-practices/SKILL.md
- vue-router-best-practicesskills/vue-router-best-practices/SKILL.md
- vue-testing-best-practicesskills/vue-testing-best-practices/SKILL.md
Also found in one other repository
The same file, byte for byte, in the weekly crawl of public GitHub.
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

