← Other topics

Vue.js Simplified - Composition API (#14)

Series contents:

Video Notes

So far in this series we’ve been using Vue’s Options API, where Vue instances are organized by options - e.g. data properties, computed properties, watchers, etc.

Another coding style that Vue provides is called the Composition API where Vue instances are organized by the application’s features. For example, if we were building a e-commerce shopping cart we could organize our instances around features like add to cart, remove from cart, update quantity, etc.

The Options API is the original way Vue worked, while the Composition API is a newer addition that was added in Vue v3. The Composition API excels when working with very robust and complex interfaces as it can provide a more intuitive way to organize your components and reuse code. That being said, the Options API is a perfectly common and valid way to work with Vue and is still appropriate for many projects.

In the Vue docs, you can toggle between the Options and Composition API:

Example setup

Preface aside, the best way to understand the difference between the Options and Composition API is to see an example, so let’s refactor FlashWord to use the Composition API. Because this will be taking our code base in a notably new direction, let’s set it up as a new project, just so we can keep the original Options API version for reference. To expedite things, we’ll start this new project as a duplicate of our existing flashword-vite application and build off of that.

Duplicate flashword-vite directory to a new directory called flashword-comp-api:

> cp -r flashword-vite flashword-comp-api

Move into the new directory:

> cd flashword-comp-api

Remove the existing node_modules subdirectory so we can rebuild it:

> rm -rf node_modules

Rebuild the node_modules subdirectory:

> npm install

Start the Vite dev server:

> npm run dev

Replace the JavaScript of /src/App.vue with this new Composition API code:

<script setup>
import { ref, computed, watch } from 'vue'
import WordCard from './components/WordCard.vue'

// Data properties
const correctCount = ref(0);
const correct = ref(false);
const completed = ref(false);
const words = ref([
        word_a: 'hola',
        word_b: 'hello',
        hint: 'greeting',
        answer: '',
        correct: false
        word_a: 'uno',
        word_b: 'one',
        hint: 'number',
        answer: '',
        correct: false
        word_a: 'gris',
        word_b: 'grey',
        hint: 'color',
        answer: '',
        correct: false

// Computed properties
const shuffledWords = computed(() => {
    return words.value.sort(() => .5 - Math.random());

const wordCount = computed(() => {
    return words.value.length;

// Watchers
watch(correctCount, (newValue, oldValue) => {
    completed.value = correctCount.value == wordCount.value;

// Methods
const incrementCorrectCount = () => {

With our example set up, let’s dig in...

Coding with the Composition API

The key idea of the Composition API is that rather than building a component via Vue object properties, we define them as constants that utilize Vue methods.

To understand this, below is a side by side comparison of FlashWord’s App.vue, where the left side is the original written with the Options API and the right side is the updated Composition API code:

Observations about the above code:

  • <script> is updated to <script setup>, a special attribute Vue provides for Single File Components that indicates we’re using the Composition API (ref).
  • Instead of exporting an object of options, we define individual JavaScript constants. We set these constants to special Vue methods:
    • The ref method is used to creative reactive data - it’s the equivalent of the Options API data option.
    • The computed method is used to create computed properties.
    • The watch method is used to define watchers.
    • Methods are defined like regular JavaScript methods - no special Vue method needed.
  • When referencing data or computed properties, we no longer use the this keyword as we’re no longer working in the context of an object. Instead, we can directly reference our constants, but we do have to append a value method to access the underlying data (ref).
  • We do not have to explicitly register components - as long as they’re imported they are available in Single File Components when using the setup attribute.
  • None of the work in the HTML template needs to change when switching between the Options and Composition API.

What does this get us?

We’ve now learned that all of the options we have available via the Options API are made available in the Composition API via methods. This frees us up to reorganize our components by feature instead of by option.

For example, imagine we were building an e-commerce site and we had a component with two features, we’ll call them Search and Add to Cart

Each feature requires, hypothetically, a mixture of data, computed properties, and watchers.

In the Options API, our resulting component would be organized by options like this:

  • Data
    • Search feature reactive data
    • Add to Cart feature reactive data
  • Computed
    • Search feature computed code
    • Add to Cart feature computed code
  • Watch
    • Search feature watcher code
    • Add to Cart feature watcher code

With the Composition API, our resulting component would be organized by features instead of options:

  • Search feature
    • reactive data
    • computed
    • watch
  • Add to Cart feature
    • reactive data
    • computed
    • watch

Much more logical, right?

Composition functions: Another benefit of the Composition API is code reusability - because it gives us access to Vue utilities (reactive data, computed properties, etc.) outside the context of a component, we could extract shared logic into their own functions that can be imported and used within different components of our application.

Updating WordCard.vue to use the Composition API

Building on what we’ve learned so far, we can update WordCard.vue’s JavaScript to also use the Composition API.

This will require the introduction of two new methods: defineProps and defineEmits:

<script setup>
// defineProps is a compile-time macro that is only available inside <script setup> and does not need to be explicitly imported. 
// https://vuejs.org/guide/essentials/component-basics.html#passing-props
const props = defineProps(['word'])

// Similar to defineProps, defineEmits is only usable in <script setup> and doesn’t need to be imported. 
// It returns an emit function that is equivalent to the $emit method.
// It can be used to emit events in the <script setup> section of a component, where $emit isn't directly accessible
const emit = defineEmits(['incrementCorrectCount'])

// Method
const checkAnswer = () => {

    // Note how props are accessed via our `props` constant defined above
    props.word.correct = props.word.word_b == props.word.answer;

    if (props.word.correct) {



If you have questions or any issues when running through the above notes, post a comment on the video on YouTube. I monitor all my comments and will do my best to respond promptly!

← Other topics