Reusable components are the foundation of scalable Vue 3 applications. By designing components that are flexible, predictable, and easy to maintain, you can reduce duplication and keep your codebase clean as it grows.
Keep Components Focused
A reusable component should have one clear responsibility. Instead of building large components that handle multiple concerns, split them into smaller ones.
Bad example (too much responsibility):
- Fetching data
- Formatting UI
- Handling user actions
Good example:
- One component displays data
- Another handles data fetching
- Logic is extracted into composables
Use Props for Configuration, Not Logic
Props should configure behavior, not control internal logic flow
<BaseButton :loading="isSaving" variant="primary" />
This keeps the component flexible without exposing internal details.
defineProps({
loading: Boolean,
variant: {
type: String,
default: 'default'
}
});
Emit Events Instead of Mutating State
Reusable components should never modify parent state directly. Use events to communicate upward.
<BaseInput
:model-value="email"
@update:model-value="email = $event"
/>
This makes the component predictable and easy to reuse in different contexts.
Prefer v-model Contracts in Vue 3
Vue 3 allows custom v-model bindings, which makes components feel natural to use.
<MyInput v-model:value="username" />
defineEmits(['update:value']);
This creates a clear and standardized API for consumers of your component.
Extract Logic into Composables
When multiple components share behavior, extract the logic into a composable instead of duplicating code.
export function useToggle() {
const isOpen = ref(false);
const toggle = () => (isOpen.value = !isOpen.value);
return { isOpen, toggle };
}
Composable functions improve reusability without coupling UI elements together.
Avoid Hard-Coded Styles and Content
Use slots to allow flexible content injection.
Reusable component (BaseCard.vue)
<template>
<div class="card">
<slot />
</div>
</template>
<BaseCard>
<template #header>Title</template>
<p>Content goes here</p>
</BaseCard>
Slots allow components to adapt to different use cases without modification.
Without slots ❌:
<div class="card">
<h3>Title</h3>
<p>Fixed content</p>
</div>
Design Stable Component APIs
Reusable components should change rarely. A stable API (props, emits, slots) ensures that refactoring doesn’t break consumers.
Conclusion
Building reusable components in Vue 3 is about clarity, separation of concerns, and stable APIs. By leveraging props, emits, slots, composables, and Vue 3’s improved v-model, you can create components that scale with your application instead of slowing it down.