# Vue 3 Composables Standards · VUE-03

Composables encourage encapsulation of reusable logic, which can then be shared across multiple components. Offering improved maintainability, debugging and readibility.

## Standard Metadata

- Area: Vue
- Owner: Frontend Steering Group
- Last reviewed: 2026-09-09
- Next review due from: 2026-12-01
- Enforcement: Code review
- Status: Active

## Organising Composables

Structure and name composables to aide discoverability.

### Naming Convention

#### Prefix Composable Function Names with `use` · VUE-03.1 · **MUST**

Start composable function names with `use`.

#### Use Functionality-Based Descriptive Names · VUE-03.2 · **MUST**

Name composables based on their functionality. When this is difficult, assess adherence to the Single Responsibility Principle.

### File Structure

#### Store Composables in a Dedicated Directory · VUE-03.3 · **MUST**

Locations should be stored in `src/composables`

#### Organise Composables by Area · VUE-03.4 · **SHOULD**

Group related composables in subdirectories if necessary.

> e.g. src/composables/forms/

### Documentation

#### Provide Clear Documentation · VUE-03.5 · **SHOULD**

Use comments and JSDoc for composable functions to explain their purpose and usage.

The JSDoc should include examples, when appropriate.

##### Documentation Example

```ts
/**
 * A composable function to manage a counter.
 *
 * @param {number} initialValue - The initial value of the counter. Defaults to 0.
 * @returns {Object} An object containing:
 *   - {Ref<number>} count - The current value of the counter.
 *   - {Function} increment - A function to increment the counter.
 *   - {Function} reset - A function to reset the counter to its initial value.
 *
 * @example
 * import { useCounter } from '@/composables/useCounter';
 * 
 * const { count, increment, reset } = useCounter();
 * 
 * // Usage in a component:
 * // <button @click="increment">Increment</button>
 * // <button @click="reset">Reset</button>
 * // <p>Current count: {{ count }}</p>
 */
export function useCounter(initialValue = 0) {
  // Define a reactive reference for the counter value
  const count = ref(initialValue);

  /**
   * Increment the counter by 1.
   */
  function increment() {
    count.value++;
  }

  /**
   * Reset the counter to the initial value.
   */
  function reset() {
    count.value = initialValue;
  }

  return { count, increment, reset };
}

```

## Creating Composables

Use composables to facilitate the reuse of logic across components and promote a modular architecture.

### Extract Reusable Lifecycle Logic into Composables or Helpers · VUE-03.6 · **MUST**

A composable is within a Vue component scope, it has access to `onMounted`, `useRoute`, `useStore` etc.

This means it should be used for reusable logic which depends on Vue's component lifecycles.

If the logic doesn't depend on a component lifecycle, it can be moved into a basic TS Helper file.

#### Lifecycle Composable Example

```ts
import { onMounted, onUnmounted } from 'vue';

/**
 * A composable function to log messages during component lifecycle events.
 *
 * @param {string} componentName - The name of the component using the composable.
 * @returns {void}
 *
 * @example
 * import { useLifecycleLogger } from '@/composables/useLifecycleLogger';
 * useLifecycleLogger('MyComponent');
 */
export function useLifecycleLogger(componentName) {
  /**
   * Log a message when the component is mounted.
   */
  onMounted(() => {
    console.log(`${componentName} mounted.`);
  });

  /**
   * Log a message when the component is unmounted.
   */
  onUnmounted(() => {
    console.log(`${componentName} unmounted.`);
  });
}

```

```ts
<template>
  <div>
    <p>My Component</p>
  </div>
</template>

<script setup>
import { useLifecycleLogger } from 'src/composables/useLifecycleLogger';

useLifecycleLogger('MyComponent');
</script>
```
