---
title: Colocate Template, Script, and Style in SFCs for Maintainability
impact: MEDIUM
impactDescription: Separating template, logic, and styles into different files reduces component cohesion and maintainability
type: best-practice
tags: [vue3, sfc, architecture, separation-of-concerns, maintainability]
---
# Colocate Template, Script, and Style in SFCs for Maintainability
**Impact: MEDIUM** - Vue SFCs are designed to colocate template, logic, and styles because these concerns are inherently coupled within a component. Separating them into different files based on file type (not concern) makes components harder to understand and maintain.
## Task Checklist
- [ ] Keep template, script, and style in the same `.vue` file by default
- [ ] Only use `src` imports when files become extremely large (500+ lines)
- [ ] Group related components in folders rather than separating by file type
- [ ] Use component composition to manage complexity instead of file splitting
**Not Recommended:**
```
components/
├── UserCard.vue # Just template
├── UserCard.js # Logic
├── UserCard.css # Styles
```
**Recommended:**
```vue
{{ displayName }}
{{ isOnline ? 'Online' : 'Offline' }}
```
## Why Colocation is Preferred
### 1. Coupled Concerns Should Stay Together
Template, logic, and styles within a component are inherently coupled:
- Template references reactive data from the script
- Styles target classes used in the template
- Changes in one often require changes in others
```vue
...
```
### 2. Easier Navigation and Understanding
Single file = single place to look:
```vue
```
### 3. Better Refactoring Experience
Renaming a class? Everything is in one file:
```vue
```
## When Src Imports Are Acceptable
For genuinely large components (rare), use src imports:
```vue
```
But first, consider if the component should be split into smaller components.
## Managing Complexity Without File Splitting
### Extract Logic to Composables
```typescript
// composables/useDataTable.ts
export function useDataTable(initialData: Ref) {
const sortColumn = ref(null)
const sortDirection = ref<'asc' | 'desc'>('asc')
const currentPage = ref(1)
const sortedData = computed(() => { ... })
const paginatedData = computed(() => { ... })
function sort(column: string) { ... }
function goToPage(page: number) { ... }
return {
sortColumn,
sortDirection,
currentPage,
sortedData,
paginatedData,
sort,
goToPage
}
}
```
```vue
```
### Break Into Smaller Components
```vue
```
## The Real Separation of Concerns
True separation of concerns in Vue means:
- **Components** handle their own template/logic/style (coupled by nature)
- **Composables** handle reusable stateful logic
- **Utilities** handle pure functions
- **Stores** handle global state
This is more maintainable than separating HTML/CSS/JS into different files.
## Reference
- [Vue.js SFC Introduction](https://vuejs.org/guide/scaling-up/sfc.html#what-about-separation-of-concerns)
- [Vue.js SFC Src Imports](https://vuejs.org/api/sfc-spec.html#src-imports)