Composables: Reusable Composition Functions
Extract reactive logic into composable functions prefixed with use, share them across components, and understand how they differ from mixins.
Composables: Reusable Composition Functions is a free Frontend Academy lesson on CoddyKit. This is lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, and your progress syncs across the web and the CoddyKit app. The Frontend Academy course includes 4 lessons in total.
What Are Composables?
A composable is a function that uses Composition API hooks to encapsulate and reuse stateful logic. They're the Composition API equivalent of mixins — but without namespace collisions or hidden dependencies.
A Basic Composable
Extract reactive logic into a function starting with use. It can use ref, computed, watch, and lifecycle hooks — just like setup().
// useCounter.ts
import { ref } from 'vue';
export function useCounter(initial = 0) {
const count = ref(initial);
const increment = () => count.value++;
const decrement = () => count.value--;
const reset = () => (count.value = initial);
return { count, increment, decrement, reset };
}
// Usage in any component:
const { count, increment } = useCounter(10);Composable with Lifecycle Hooks
Composables can register lifecycle hooks. The hooks fire relative to the component that calls the composable.
// useOnlineStatus.ts
import { ref, onMounted, onUnmounted } from 'vue';
export function useOnlineStatus() {
const isOnline = ref(navigator.onLine);
const update = () => (isOnline.value = navigator.onLine);
onMounted(() => {
window.addEventListener('online', update);
window.addEventListener('offline', update);
});
onUnmounted(() => {
window.removeEventListener('online', update);
window.removeEventListener('offline', update);
});
return { isOnline };
}Composable with Async (useFetch)
Composables work great for async data fetching — encapsulate the loading/error/data pattern.
// useFetch.ts
export function useFetch<T>(url: MaybeRef<string>) {
const data = ref<T | null>(null);
const loading = ref(true);
const error = ref<string | null>(null);
watchEffect(async (onCleanup) => {
const controller = new AbortController();
onCleanup(() => controller.abort());
loading.value = true;
error.value = null;
try {
const res = await fetch(unref(url), { signal: controller.signal });
data.value = await res.json();
} catch (e: any) {
if (e.name !== 'AbortError') error.value = e.message;
} finally { loading.value = false; }
});
return { data, loading, error };
}Accepting Refs as Parameters
Composables can accept either plain values or refs as arguments using MaybeRef<T> (= T | Ref<T>) and unref() to access the value.
import type { MaybeRef } from 'vue';
import { unref } from 'vue';
function useDouble(num: MaybeRef<number>) {
return computed(() => unref(num) * 2);
}Composables vs Mixins
Mixins inject properties into the component without clear origin. Composables are explicit — you see exactly what a composable provides from its return value. Multiple composables can be used without naming conflicts.
Sharing State Between Components
If a composable calls ref() inside itself, each component that calls the composable gets its own state. To share state across components, call ref() at module scope (outside the composable function).
// Shared state (module-level):
const sharedCount = ref(0);
export function useSharedCounter() {
// All callers share the same sharedCount
return { count: sharedCount, increment: () => sharedCount.value++ };
}Composable Libraries
VueUse (vueuse.org) provides 200+ ready-to-use composables: useLocalStorage, useFetch, useDark, useIntersectionObserver, and many more. Always check VueUse before writing from scratch.
Testing Composables
Test composables by calling them inside a small test component or using @vue/test-utils mountedApp pattern. Vitest integrates well with Vue's reactivity system.
Composable Naming Conventions
Always prefix with use (useAuth, useFetch, useMediaQuery). Keep them focused on a single concern. Avoid composables that do too many unrelated things.
Composable Organisation
Create a composables/ folder. One file per composable. Index file re-exports all composables. This mirrors how custom hooks are organised in React projects.
Quick Check
What is the key advantage of composables over Vue mixins?
Recap: Vue Composables
A composable is a use-prefixed function that calls Composition API hooks. Each caller gets independent state unless you use module-level refs. Accept refs or values with MaybeRef + unref. Register lifecycle hooks inside composables. Check VueUse before writing your own. Explicit return values prevent mixin-style namespace pollution.
Learn HTML with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 41
- Lessons
- 163
Frequently Asked Questions
Is the “Composables: Reusable Composition Functions” lesson free?
Yes — the full text of “Composables: Reusable Composition Functions” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO. The Frontend Academy course includes 4 lessons in total.
What will I learn in “Composables: Reusable Composition Functions”?
Extract reactive logic into composable functions prefixed with use, share them across components, and understand how they differ from mixins. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Frontend Academy?
No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.
How long does the “Composables: Reusable Composition Functions” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Frontend Academy lesson?
Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- ref() and reactive()
- computed() and watch()
- The setup() Function and script setup
- Composables: Reusable Composition Functions