Skip to content

Organize composable code by logical concern

Within composables, group related code together by feature/concern rather than by Vue API type. Don't cluster all refs in one place, all computed in another, and all watchers elsewhere.

Grouping by concern keeps related logic together, making it easier to understand, maintain, and extract into smaller composables when needed.

Internal ordering

Within each concern group, follow this order: state → metadata (loading, error) → methods → return statement. This creates a consistent reading flow across all composables.

Example:

typescript
// Good - grouped by concern
function useUserProfile(userId: Ref<string>) {
  // User data concern
  const user = ref<User | null>(null)
  const isLoading = ref(false)
  const fetchUser = async () => { /* ... */ }

  // Avatar concern
  const avatarUrl = computed(() => user.value?.avatar ?? defaultAvatar)
  const updateAvatar = async (file: File) => { /* ... */ }

  return { user, isLoading, avatarUrl, fetchUser, updateAvatar }
}

// Bad - grouped by API type
function useUserProfile(userId: Ref<string>) {
  // All refs together
  const user = ref(null)
  const isLoading = ref(false)

  // All computed together
  const avatarUrl = computed(() => /* ... */)

  // All functions together
  const fetchUser = async () => { /* ... */ }
  const updateAvatar = async () => { /* ... */ }
}

Rule for AI agents

- PREFER grouping composable code by concern/feature, not by Vue API type (refs, computed, watchers)

Eslint rule

No ESLint rule available

Source