How to use computed() in Vue 3
computed() creates a cached reactive value derived from other reactive state — it recalculates only when its dependencies change, making it more efficient than calling a method in the template on every render.
As the creator of CoreUI with Vue development experience since 2014, I use computed() extensively in CoreUI Vue components for filtering, sorting, and formatting data that depends on reactive state.
The most important distinction from a regular method is caching — if the dependencies haven’t changed, Vue returns the cached result instantly without re-running the function.
This makes computed the right choice for any derived value accessed in a template.
Create a computed property that derives a value from reactive state.
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const age = ref(25)
// Computed - recalculates only when firstName or lastName changes
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
const isAdult = computed(() => age.value >= 18)
// Access like a ref - read with .value in JS, auto-unwrapped in templates
console.log(fullName.value) // 'John Doe'
firstName.value = 'Jane'
console.log(fullName.value) // 'Jane Doe' - recalculated
<template>
<!-- No .value needed in templates -->
<p>{{ fullName }}</p>
<p v-if="isAdult">Adult user</p>
</template>
computed returns a read-only ref. Accessing .value in JavaScript gives the computed result. Vue tracks which reactive values are read inside the getter and only re-runs it when one of them changes.
Filtering and Sorting Lists
Derived list transformations are the most common use case for computed.
<template>
<div>
<input v-model="search" placeholder="Search..." />
<select v-model="sortBy">
<option value="name">Name</option>
<option value="email">Email</option>
</select>
<ul>
<li v-for="user in filteredUsers" :key="user.id">
{{ user.name }} — {{ user.email }}
</li>
</ul>
<p>{{ filteredUsers.length }} results</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const users = ref([
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
{ id: 3, name: 'Charlie', email: '[email protected]' }
])
const search = ref('')
const sortBy = ref('name')
const filteredUsers = computed(() => {
const query = search.value.toLowerCase()
const filtered = query
? users.value.filter(u =>
u.name.toLowerCase().includes(query) ||
u.email.toLowerCase().includes(query)
)
: users.value
return [...filtered].sort((a, b) =>
a[sortBy.value].localeCompare(b[sortBy.value])
)
})
</script>
The computed recalculates whenever users, search, or sortBy changes. Using spread [...filtered] before sorting avoids mutating the original array. The {{ filteredUsers.length }} in the template reads the same cached result — Vue doesn’t run the filter/sort twice.
Writable Computed
Create a computed that has both a getter and setter.
import { ref, computed } from 'vue'
const temperature = ref(0) // Celsius
const fahrenheit = computed({
get: () => temperature.value * 9 / 5 + 32,
set: (val) => {
temperature.value = (val - 32) * 5 / 9
}
})
fahrenheit.value = 212 // Sets temperature to 100°C
console.log(temperature.value) // 100
Writable computeds are useful for two-way conversions. The setter translates the input value back to the source state. Assigning to fahrenheit.value updates temperature, which triggers the getter to recalculate.
Best Practice Note
In CoreUI Vue components we use computed() for any value derived from ref or reactive state that is accessed in templates — never compute in methods if the value is referenced multiple times or is expensive. Avoid side effects inside computed getters (no API calls, no state mutations). For effects with side effects, use watchEffect() or watch() instead. See how to use watch() in Vue 3 for reactive responses that need to perform actions rather than derive values.



