I find myself spending very little time enjoying Vue. Which is not to say I hate it, but that I don't have a lot of fun with it โ€” I've reached a sort of intellectual detente with the framework, and most of my "fun frontend time" is spent in pure functional TypeScript. But I was delighted to discover a change in Vue 3.4 that makes life 2% better (and I do not mean that to damn with faint praise โ€” 2% is a lot!).


Historically, declaring a component with a value that can/should be updated requires a slew of boilerplate:

<template>
  <input
    type="text"
    :value="modelValue"
    @input="
      emit('update:modelValue', ($event.target as HTMLInputElement).value)
    "
  />
</template>

<script lang="ts" setup>
defineProps<{
  modelValue: string;
}>();

defineEmits<{
  "update:modelValue": string;
}>();
</script>

Vue 3.4 shipped support for the glorious defineModel macro, which makes this all much simpler:

<template>
  <input
    type="text"
    v-model="modelValue"
  />
</template>

<script lang='ts' setup>
defineModel<string>();
</script>

This is not paradigm-shifting, but it is both quite nice and conceptually clarifying. I'm very grateful for the addition, and excited to slowly backport a whole bunch of boilerplate.

Lightning bolt
About the author

I'm Justin Duke โ€” a software engineer, writer, and founder. I currently work as the CEO of Buttondown, the best way to start and grow your newsletter, and as a partner at Third South Capital.

Lightning bolt
Greatest hits

Lightning bolt
Elsewhere

Lightning bolt
Don't miss the next essay

Get a monthly roundup of everything I've written: no ads, no nonsense.