Engineering/Coding Standards/TypeScript/Vue/Vue Composables/

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.

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
/**
 * 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

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(<code>${componentName} mounted.</code>);
  });

  /**
   * Log a message when the component is unmounted.
   */
  onUnmounted(() => {
    console.log(<code>${componentName} unmounted.</code>);
  });
}
<template>
  <div>
    <p>My Component</p>
  </div>
</template>

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

useLifecycleLogger('MyComponent');
</script>