Vue Computed Get Set: How to Create Writable Computed Properties in Vue 3

Use the object syntax computed({ get: () => ..., set: (val) => ... }) to create a writable computed ref that can be read and assigned to like a standard ref.

When working with the Composition API in Vue 3, you often need derived state that also supports two-way binding. The vue computed get set pattern allows you to define both a getter for deriving values and a setter for propagating changes back to source state. Internally, the Vue core repository (vuejs/core) implements this through the computed() function in packages/reactivity/src/computed.ts, which creates a WritableComputedRefImpl instance when it detects an object with get and set methods.

Understanding the Vue Computed Get Set Syntax

By default, computed() accepts a single getter function and returns a readonly ref. To enable the vue computed get set behavior, you pass an object containing both get and set properties:

import { computed, ref } from 'vue'

const count = ref(0)

const doubled = computed({
  get: () => count.value * 2,
  set: (val: number) => {
    count.value = val / 2
  }
})

In this pattern, doubled.value reads from the getter, while assigning to doubled.value = 10 invokes the setter, which updates the underlying count ref.

How Writable Computed Works Under the Hood

When you provide an object with get and set, the computed() factory in packages/reactivity/src/computed.ts instantiates a WritableComputedRefImpl class. This implementation:

  1. Wraps the getter in a ReactiveEffect to track reactive dependencies
  2. Stores the setter function for later invocation when the ref receives a new value
  3. Exposes the standard Ref interface with .value property, allowing seamless integration with the template proxy system

The ReactiveEffect ensures that when dependencies inside the getter change, the computed value invalidates its cache and re-evaluates on the next access, maintaining Vue's efficient reactivity guarantees.

Vue Computed Get Set Implementation Details

The architectural flow for a writable computed property follows these specific steps as implemented in the Vue core:

Step Implementation Detail Source Location
1. Object Detection computed() checks if the argument is an object with get and set methods, distinguishing it from a simple getter function. packages/reactivity/src/computed.ts
2. Effect Creation The getter is wrapped in a ReactiveEffect that tracks reactive dependencies accessed during execution. packages/reactivity/src/computed.ts
3. Setter Storage The provided set function is stored on the WritableComputedRefImpl instance for invocation during write operations. packages/reactivity/src/computed.ts
4. Ref Interface The instance implements the Ref interface, exposing a .value property that triggers getter/setter logic appropriately. packages/reactivity/__tests__/computed.spec.ts

This architecture ensures that vue computed get set properties remain fully reactive while providing controlled mutation capabilities through the setter interface.

Practical Vue Computed Get Set Example

Here is a complete, runnable example demonstrating a writable computed property that synchronizes a full name with separate first and last name refs:

import { ref, computed, defineComponent } from 'vue'

export default defineComponent({
  setup() {
    // Source reactive state
    const firstName = ref('Ada')
    const lastName = ref('Lovelace')

    // Writable computed with get and set
    const fullName = computed({
      get() {
        // Derive full name from parts
        return `${firstName.value} ${lastName.value}`
      },
      set(newValue: string) {
        // Parse and update source refs
        const [first, ...rest] = newValue.split(' ')
        firstName.value = first
        lastName.value = rest.join(' ')
      }
    })

    // Reading the computed
    console.log(fullName.value) // "Ada Lovelace"

    // Writing to the computed triggers the setter
    fullName.value = 'Grace Hopper'
    console.log(firstName.value) // "Grace"
    console.log(lastName.value)  // "Hopper"

    return { firstName, lastName, fullName }
  }
})

Template Usage with v-model

The vue computed get set pattern enables seamless two-way binding in templates:

<template>
  <div>
    <p>First: {{ firstName }}</p>
    <p>Last: {{ lastName }}</p>
    
    <!-- Two-way binding works because fullName has a setter -->
    <input v-model="fullName" placeholder="Enter full name" />
  </div>
</template>

When the user types in the input, v-model automatically invokes the setter, which parses the string and updates the underlying firstName and lastName refs.

Key Source Files for Vue Computed Get Set

Understanding the implementation requires examining these specific files in the vuejs/core repository:

File Purpose
packages/reactivity/src/computed.ts Core implementation of computed(), including WritableComputedRefImpl class and ReactiveEffect integration for getters.
packages/reactivity/__tests__/computed.spec.ts Comprehensive test suite validating writable computed behavior, including setter invocation and reactivity edge cases.
packages/reactivity/__benchmarks__/computed.bench.ts Performance benchmarks demonstrating the efficiency of the computed effect scheduling system.

These files demonstrate how Vue maintains reactivity performance while supporting the vue computed get set pattern through careful effect tracking and cache invalidation.

Summary

  • Vue computed get set properties are created by passing an object with get and set methods to computed() in the Composition API.
  • The implementation resides in packages/reactivity/src/computed.ts, which creates a WritableComputedRefImpl instance wrapping the getter in a ReactiveEffect.
  • Writable computed refs expose the standard .value interface, enabling both reading (via getter) and writing (via setter) while maintaining full reactivity.
  • This pattern supports two-way binding with v-model in templates, allowing computed properties to serve as bridges between UI inputs and source state.

Frequently Asked Questions

Can you use vue computed get set with the Options API?

Yes, the Options API supports writable computed properties through the same get and set syntax within the computed option of a component. While the syntax differs from the Composition API's computed() function, the underlying reactivity system in packages/reactivity/src/computed.ts handles both approaches identically.

What happens if you assign to a computed without a setter?

If you attempt to assign to a computed property that was created with only a getter function (the default), Vue will throw a runtime warning stating "Write operation failed: computed value is readonly." This protection ensures that derived state cannot be accidentally mutated without an explicit setter defining the mutation logic.

How does Vue track dependencies in a writable computed?

Vue wraps the get function in a ReactiveEffect instance when creating the computed ref. During execution of the getter, any accessed reactive values (refs or reactive objects) are automatically tracked as dependencies. When those dependencies change, the effect triggers, invalidating the computed cache and scheduling a re-evaluation for the next read operation.

Is there a performance difference between readonly and writable computed?

There is no significant performance difference between readonly and writable computed properties in Vue 3. Both use the same ReactiveEffect mechanism for dependency tracking and caching. The only additional overhead for writable computed is the storage of the setter function reference, which is negligible compared to the cost of effect scheduling and re-evaluation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →