Skip to content

Custom Composable Methods with Vue 3

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Introduction

One of the greatest strenghts of modern Javascript frameworks is the ability to reuse components. Components (especially Vue's single-file components) allow you to build a reusable piece of code that handles the template, styling, and logic for a part of your application. Building frontend applications with components is fairly ubiquitous at this point, with the most popular frameworks all adopting this style of building an application.

However, there are times that you need to share code between components. Either it's a utility to help with form validation or an API request that needs to be made from different parts of your application. Maybe it's a timer, where the rendering of the countdown is different depending on what page you're on. Whatever the case may be, you will find yourself in a situation where building a component ends up duplicating code rather than reducing it.

Until Vue 3 and the Composition API, we had two methods of handling this - utility functions imported for a single use or implementing mixins for our Vue components. Utility functions can do a lot, but they are typically framework agnostic and do not handle state or other Vue features. Mixins can cover a large number of cases, but they cause a lot of issues on their own:

  • Multiple mixins could use the same key names, causing values to be different than expected.
  • It's not obvious what methods and attributes are available within a component, leading to confusion about what is and is not present on this.
  • While they help with reusing logic in multiple components, we can't pass parameters into a mixin to customize it for our needs. This leads mixins to be a bit too rigid in practice, and end up being less reusable than we'd like.

In this article, we will explore new options for creating reusable code - custom methods using the Vue 3 Composition API.

If you haven't read my previous articles on the Composition API, I highly recommend reading them before we continue. We won't be using all of these concepts in this article, but it's helpful to keep in mind everything you can do with the Composition API.

Example - Weight Conversion

Let's start with an example of a mixin where we convert a weight to other weight scales. It allows us to configure whether the weight is pounds or kilograms, and uses computed properties to generate the correct measure for each type we want to support. For this example, we will handle pounds, kilograms, metric tons, and short tons.

Here's what that mixin might look like:

import { defineComponent } from "vue";

export default defineComponent({
  data() {
    return {
      weight: 0,
      weightType: "LBS",
    };
  },
  computed: {
    lbs() {
      return this.weightType === "LBS"
        ? this.weight
        : this.weight * 2.20462262185;
    },
    kg() {
      return this.weightType === "LBS" ? this.weight : this.lbs * 0.45359237;
    },
    mt() {
      return this.kg * 0.001;
    },
    st() {
      return this.lbs / 2000;
    },
  },
});

Great! Now in our template we can bind to weight and weightType and utilize the various weights as needed. There are a couple problems with this mixin, however. Because of its nature, it won't be obvious within the component which weights are supported. What if another developer is expecting imperial tons? Or grams? By using this mixin, the developer would need to examine the mixin in order to know for certain what was available.

Also, there is a risk that any of these values could be overridden within the component. If this.lbs is defined anywhere else, it will probably cause errors with the other computed properties. This is due to the mixin not being encapsulated from the rest of the component.

Let's address both of these problems by converting this mixin to a custom Composition API method. We'll still have the benefits of using computed properties and triggering Vue's reactivity system, but the code will be more explicit to future developers.

import { ref, computed } from "vue";

export default function useWeights(
  initialWeight: number = 0,
  initialWeightType: "LBS" | "KG" = "LBS"
) {
  const weight = ref(initialWeight);
  const weightType = ref(initialWeightType);

  const lbs = computed(() =>
    weightType.value === "LBS" ? weight.value : weight.value * 2.20462262185
  );
  const kg = computed(() =>
    weightType.value === "KG" ? weight.value : lbs.value * 0.45359237
  );
  const mt = computed(() => kg.value * 0.001);
  const st = computed(() => lbs.value / 2000);

  return {
    weight,
    weightType,
    lbs,
    mt,
    st,
    kg,
  };
}

Let's go over what we're doing here:

  1. We have created a function that is the default export called useWeights. This is a common naming scheme in React for similar types of functions (custom hooks) and has been picked up in the Vue community as well.
  2. We're using ref to store two local variables - weight and weightType. Because we are using ref, any updates to them will trigger Vue template rendering and the computed properties will recalculate.
  3. We are using computed to create four computed properties, just like in our mixin.
  4. We then return the refs and computed properties.

Now, in our Vue component, we can import this function and use it to access these variables.

import { defineComponent } from "vue";
import useWeights from "./hooks/useWeights";

export default defineComponent({
  name: "App",
  setup() {
    let { weight, weightType, lbs, kg, mt, st } = useWeights();

    return {
      weight,
      weightType,
      lbs,
      kg,
      mt,
      st,
    };
  },
});

By utilizing our useWeights function, we can instantiate the values needed to perform our weight conversions. All of the logic to handle our conversions is bundled inside of the custom function, which means there's no chance of accidentally changing what lbs is supposed to be. And because we are destructuring the return from useWeights, we have full control over the variable names being returned, and they are explicitly set in our component. No more guessing what values are available!

For those of you familiar with Typescript, you may have noticed that our useWeights function implements a small amount of type checking for its inputs. The weightType, for example, has the implicit type of Ref<"LBS" | "KG">. This means that in our Vue component, we can see exactly what types are expected, and even get proper error messaging. For example, setting weightType.value to an unexpected value of "MT" causes the Typescript error, Type '"MT"' is not assignable to type '"LBS" | "KG"'. This isn't as simple to get if we were using mixins!

Example - API Requests

Let's look at another example of a custom Composition API function - making API requests. This is a great example because we can bundle a lot of logic that we'd otherwise need to handle in our component.

import { ref } from "vue";

export const Status = {
  IDLE: "IDLE",
  RUNNING: "RUNNING",
  SUCCESS: "SUCCESS",
  ERROR: "ERROR",
};

export default async function useDadJoke() {
  async function fetchJoke() {
    status.value = Status.RUNNING;
    try {
      const res = await fetch("https://icanhazdadjoke.com/", {
        method: "GET",
        headers: {
          Accept: "application/json",
        },
      });
      if (!res.ok) {
        status.value = Status.ERROR;
      }
      const json = await res.json();
      status.value = Status.SUCCESS;
      return json;
    } catch (err) {
      status.value = Status.ERROR;

      throw new Error(err);
    }
  }

  async function refetchJoke() {
    joke.value = await fetchJoke();
  }

  let status = ref(Status.IDLE);
  let joke = ref(await fetchJoke());

  return {
    joke,
    status,
    refetchJoke,
  };
}

In this function (useDadJoke), we have two more functions - fetchJoke and refetchJoke. fetchJoke is the main content here, using Fetch to make a request, confirm its status, and then return the result. refetchJoke simply calls fetchJoke and stores it on our local ref, joke.

We then declare the two refs that we need, status and joke, then return everything but fetchJoke. This provides the two refs and the refetch function to our Vue component. We can then use this custom function in our component like this:

<template>
  <div v-if="status === Status.RUNNING">Loading...</div>
  <div v-else>{{ joke.joke }}</div>
  <div>
    <button @click="refetchJoke" :disabled="status === Status.RUNNING">
      Refetch joke
    </button>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import useDadJoke, { Status } from "../hooks/useDadJoke";

export default defineComponent({
  async setup() {
    let { joke, status, refetchJoke } = await useDadJoke();

    return {
      joke,
      status,
      refetchJoke,
      Status,
    };
  },
});
</script>

As we can see, all of our logic is now contained within the custom function, and can be reused in other components as well. We could also refactor our useDadJoke function to accept a URL as an argument. We could also leverage common libraries like Axios here, and put our configuration into the custom function. This is a great example of what we can do with custom Composition API functions.

Conclusion

Custom Composition API functions have a lot of potential to clean up application code. They really highlight the benefit of what the Composition API provides - being able to group code by feature, rather than function. By breaking up your application's logic into separate functions that are then imported into components, it will be far easier to utilize that logic across your application.

In addition, keep in mind that the Composition API (and Vue's reactivity system) can be used in other contexts than a Vue single-page application. The same logic that you are using in your frontend could also work on your Node backend! By bundling this logic into functions, it helps prevent code duplication in more than just your Vue app.

One last thing - a large number of libraries are already being created to leverage custom Composition API functions. A great example of this is Vue Use by Anthony Fu, which includes a large number of functions for everyday use. Some of them include:

  • useEventListener
  • useDebounce
  • onClickOutside
  • useOnline
  • useInterval/useTimeout
  • useStorage (localStorage and sessionStorage.)

Other libraries, like Vuex and Pinia, also provide custom functions to integrate their libraries using the Composition API, with more on the way. Just like with the React ecosystem when Hooks came out, the Vue ecosystem is slowly adopting these new changes and finding where they work best. Now is a great time to start working on custom Composition API functions for your own applications!

Until next time!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

3 VueJS Component Libraries Perfect for Beginners cover image

3 VueJS Component Libraries Perfect for Beginners

For developers checking out VueJS for the first time, the initial steps are overwhelming, particularly when setting up projects from square one. But don’t worry! The VueJS ecosystem offers a plethora of remarkable component libraries, easing this early obstacle. These three libraries are pre-built toolkits, providing beginners with the means to kickstart their VueJS projects effortlessly. Let’s take a look! Quasar Quasar is among the most popular open-source component libraries for Vue.js, offering a comprehensive set of ready-to-use UI components and tools for building responsive web applications and websites. Designed with performance, flexibility, and ease of use in mind, Quasar provides developers with a wide range of customizable components, such as buttons, forms, dialogs, and layouts, along with built-in support for themes, internationalization, and accessibility. With its extensive documentation, active community support, and seamless integration with Vue CLI and Vuex, Quasar empowers developers to rapidly prototype and develop high-quality Vue.js applications for various platforms, including desktop, mobile, and PWA (Progressive Web Apps). PrimeVue PrimeVue is a popular Vue.js component library offering a wide range of customizable UI components designed for modern web applications. Developed by PrimeTek, it follows Material Design guidelines, ensuring responsiveness and accessibility across devices. With features like theming, internationalization, and advanced functionalities such as lazy loading and drag-and-drop, PrimeVue provides developers with the tools to create elegant and high-performing Vue.js applications efficiently. Supported by clear documentation, demos, and an active community, PrimeVue is an excellent choice for developers seeking to streamline their development process and deliver polished user experiences. Vuetify Vuetify is a powerful Vue.js component library that empowers developers to create elegant and responsive user interfaces with ease. Built according to Google's Material Design guidelines, Vuetify offers a vast collection of customizable UI components, ranging from buttons and cards to navigation bars and data tables. Its comprehensive set of features includes themes, typography, layout grids, and advanced components like dialogues and sliders, enabling developers to quickly build modern web applications that look and feel polished. With extensive documentation, active community support, and ongoing development, Vuetify remains a top choice for Vue.js developers seeking to streamline their workflow and deliver visually stunning user experiences. For newcomers venturing into Vue.js, the initial setup might seem daunting. Thankfully, Vue.js offers a variety of component libraries to simplify this process. Quasar, PrimeVue, and Vuetify are standout options, each providing pre-built tools to kickstart projects smoothly. Whether you prefer Quasar's extensive UI components, PrimeVue's Material Design-inspired features, or Vuetify's responsive interfaces, these libraries cater to diverse preferences and project requirements. With their clear documentation and active communities, these libraries empower developers to start Vue.js projects confidently and efficiently, enabling Vue developers to create polished user experiences....

Getting started with Vitepress cover image

Getting started with Vitepress

Getting started with Vitepress to create your blog site Have you heard about Vitepress, but you have not checked it out at it yet? Well, in this article, we are going to cover the basic setup and share what all the fuss about this new fantastic static site generator. If you are looking for something that would allow you to quickly create a static site with Markdown support, search, Light/Dark theme, advertisement, navigation, and much more, then Vitepress is what you are looking for. Suppose you want some proof of Vitepress's power without having to invest any further time, I suggest you head over to the main Vitepress site (vitepress.dev) and experience what Vitepress can do, as the official site is built on Vitepress! What is Vitepress Vitepress is a powerful Static Site Generator powered by Vite mainly used for Documentation and Blogs with the default theme, and open to customization to be used for anything you may need it to with custom themes and theme overrides.. Vitepress power comes from its low learning curve, powerful configuration settings, and the ability to easily customize it. For example, internationalization is built-in, Theme toggling is built-in and even full-site searches require a single line in the config to be set up. What makes Vitepress so powerful is its extensive configuration and the fact that it can be customized by overriding the existing theme, creating your theme, or simply enhancing pages with custom Vue code. Prerequisites To successfully run the following demo, you will need: - Node.js version 18 or higher. - Terminal for accessing VitePress via its command line interface (CLI). - Text Editor with Markdown syntax support. - VSCode is recommended, along with the official Vue extension. Create your project To create the project, we will follow the steps shown in the official Getting Started guide. If you want to set up a Vitepress project quickly, run the following steps: - Create a new folder mkdir vitepress-tutorial - Access the folder cd vitepress-tutorial - Install Vitepress npm add -D vitepress - Run the Wizard npx vitepress init - Answer the questions: - Where should VitePress initialize the config? - Site title - Site Description - Theme - Do you want Typescript support? - run npm run docs:dev - Enjoy your site. After you run the above steps, your Vitepress will be ready and running as shown below What is available out of the box The site comes fully set up with enough to get you started. Let's see what features are available within the software: - Navbar: The site comes with a Navbar that already includes links to our blog pages - Light/Dark theme: Out of the box theming - Home page: Basic Homepage layout - Blogs: Two different blog posts with sidebar navigation All of the above is available with just 4 files! Let's move forward and see how to customize our app. Overriding the homepage It is time to modify our site by accessing its folders. What you will probably notice when opening the site, is that Vitepress follows a very simple file structure, in fact, a new installation just includes 4 extra files on top of the expected package.json and node_modules. Let's update our homepage to make it more unique. Because Vitepress follows a "file-system based router" we can find this file within the root of the project within a file called index.md. This file will be accessible at "/" or "/index.html" of your site. The content of the file is the following: ` As you can see, the file has no code in it, and it is just driven by configuration, or more specifically in this case Markdown frontmatter, that is a set of configurations accepted by markdown files that help you set up your options such as title, description, og:image. We will describe frontmatter in more detail later in the article. Before we jump into modifying the configuration of the file, you should know that Vitepress has a very extensive and well-detailed documentation site where you can find help if you are stuck or would like to learn more. In this case, we are overriding the "home" page, so the documentation can be found here: Home Page Default Theme configuration. If you read the current file within the homepage, you will notice that it defines a "layout" of "home". This layout displays a main header with CTAs and a set of feature blocks. There are three different layouts available in the Default theme: "home", "doc" and "page". The title and description have already been set from the information we provided from the installation wizard. But the rest is just a basic boiler template. Let's see what we can change: 1) Add a hero image. This image can either be externally sourced or saved within the repository. ` 2) Update the action buttons. ` As shown above, Action buttons have two themes "brand" or "alt" and can accept internal or external links. Vitepress is clever enough to set the external links to open in a new tab and set the rel="noreferrer". 3) Change the feature blocks: Features blocks are great for engaging with the user and telling them what makes your site special. This accepts an icon and some text, so let's change ours with the following: ` The homepage is now completed and updated and it should look like this: Please note that what we did on the homepage is just changing the markdown front matter of the "home" layout. What this means is that if you want to, you can easily customise the page further by either adding more blocks to the layout file or actually by writing and styling the rest of the page as normal. Site configuration In this step, we are going learn about the main site configuration and how we can use it to customize our site. The configuration file can be found in the .vitepress folder under the name of "config.mjs". Just like the homepage layout, the configuration used in the preset file is self-explanatory: ` This file is very important and you are probably going to have it open at all times as it is going to be responsible for the layout of the sidebar navigations of your site. In this section, we are going to learn how to use the Vitepress configuration file to achieve the following: - Modify the sidebar navigation - Enable Search - Add Favicon to your site Modify the sidebar navigation The sidebar is the component displayed on the left-hand side of the blog pages. This is not automatically generated, but it is manually set in this file. You can have more than one navigation, so, for example, you could specify sidebar navigation that shows in pages that have "/blog/" within their path and another one for all markdown pages that have "/tutorials/". Let's see how to implement this: ` With the above code, there will be 2 different sidebars. One will just show if the URL includes "/blog" and the other will be displayed if the path includes "tutorials". Clicking on the above items will give a 404 error as we do not have any pages in that specific location. Still, we can easily fix the issue by creating the two folders "blog" and "tutorial" and creating the required files within these folders in our case are "index.md" and "one.md" for the blog and "index.md" and "two.md" for tutorials. The sidebar has further settings like the ability to create a nested tree or create collapsable menus. You can learn more by checking out the the official documentation on default theme sidebar. Enable Search No documentation or blog site is complete until a search is fully implemented on it. Luckily for us, enabling a site-wide search is extremely simple with Vitepress. Vitepress supports two different search types: a full-text search using minisearch and Algolia based search. In this tutorial, we are going to enable the full-text search. This is fully built-in and requires no external accounts. To enable search, we need to add a "Search" parameter within our themeConfig and set the provider to "local". We can add this right below the socialLinks. ` With just a simple config change, our site will now have a full site search working as shown below: The official search documentation has further information about the look and functionality of the search. Add Favicon to your site Even if the site configuration is very extensive, there are times when you will need to add something within the site-wise page that is not available. In this section we are going to learn how to add specific attributes to the of our site, and specifically how to add a favicon. To add custom values to the head, we are going to use the "head" properties available with the Vitepress configuration. The "head" configuration is an array that accepts an array with the element type (eg. link, script, meta), and an object including all the attributes for that specific element. So for example to replicate the following HTML: ` we would define the following head config: ` We can use this technique to set up metadata and even load fonts or Google Analytics. More info in the site-config head Writing your post In the last section of this article, we are going to learn how to actually write a blog post and also learn how to customize the pages with JS and styles. Writing your first page In the previous section, we created a couple of markdown files, but they are currently empty. Let's see how to create beautiful documentation using the built-in feature of Vitepress. In this section, we are going to work on the file stored in /blog/index.md. This file can be accessed in your browser by accessing "http://localhost:5174/blog/index.html". Blog Frontmatter Every file needs to have a frontmatter defined. This is used to define basic information on the page, such as the title, description, and more. For best SEO results, it is best practice to always define a title and description for a new page. We can do this by adding the following code at the top of our file: ` Frontmatter in Markdown files are delimited by the "---". In the above code, we set our title and description. Vitepress frontmatter supports further config like lastUpdates, sidebar, outline, and more. You can find info on the frontmatter-config documentation. Frontmatter has some global configuration, such as title and description, but also "layout specific" settings that are just available on specific layouts. This is clearly explained in the documentation. Blog Markdown Now that our post frontmatter is set, it is time to write the content of it. This is done using a very extensive markdown engine. Let's start with the basics and write a heading with some text and a link as shown below: ` After saving, our development environment will show the following results: Let's add a couple of headings and a table of contents to our document using [[toc]] to the top of our page: ` The above will produce an unordered list with all our links. The last feature that I want to share about the Vitepress markdown engine is the code editors. The markdown engine used in Vitepress offers extensive features when it comes to code rendering. Features available are "code highlight", "code focus", external snippets loading and much more. The full list of features can be found in the markdown docs. Let's implement a simple code snippet with a line of code focused. This can be achieved by adding "// [!code focus]" at the end of our row. Let's give it a try: ` The output of this will be: Customize your blog with Vue In this last section, we will learn how to customize our code by adding js logic, style, and external components. Before we begin, it is important to understand that when you use the default template of Vitepress, your pages are going to be rendered with Vue. This means that we can expand the individual page's functionality by rendering other vue components and/or writing logic and styles directly on the page. To better explain this concept, we are going to create a team page. Create a file called team.md within the root of our repository. This file will be accessible on "http://localhost:5174/team.html" and will be just a simple Markdown file. First, we set up the frontmatter as before. In this case, we have to specify an additional config called "layout". This will ensure the page has no style or components loaded such as sidebar or aside. ` Then we will have to create our team variable, just like a normal Vue component; we can do so by defining a script setup tag and defining the constant there. ` In the above code, we have imported the VPTeamMembers component from the vitepress/theme and defined an array of members. The values used in the members array are hardcoded, but as you may expect, you can load this information directly from an API. We now have to use the "members" variable within our file. We can do so by writing normal JavaScript. The markdown file will evaluate the JavaScript and render it, so in the following example it will render a specific component. ` Before we move forward we need to define some style as the page is unstyled since we have loaded the layout of "page". Just like we did with the tag, we can load a tag and update our styles: ` The completed file will look like this: ` The file above now includes: - A frontmatter that specifies a "page" layout - A script tag that loads an external component and defines a variable - Styles to make the page pretty - Markdown with a custom component The completed team page would render the following: Conclusion Vitepress is an extremely flexible static site generator. Its default theme provides you with everything you need to get started quickly. The ability to load external themes, enhance the current theme, and or write custom code within your page makes this tool extremely powerful. In future articles, we will discover what components are available within the Default Theme and see how you can make the most of your Vitepress site but keep on coding....

Vue 3.2 - Using Composition API with Script Setup cover image

Vue 3.2 - Using Composition API with Script Setup

Introduction Vue 3 introduced the Composition API as a new way to work with reactive state in a Vue application. Rather than organizing code by functionality, (data, computed, methods, watch, etc), you can group code by feature (users, API, form). This allows for a greater amount of flexibility while building a Vue application. We've already talked about the Composition in other articles (if you haven't read them, check them out!), but with the release of Vue 3.2, another Composition-related feature has been released as stable - . In short, allows developers to define a component without having to export anything from your JavaScript block - simply define your variables and use them in your template! This style of writing a component resembles Svelte in many ways, and is a massive improvement for anyone coming into Vue for the first time. Basics Let's look at an example. If you were using the Options API (the standard of Vue 2), all of your single-file components would look something like this: ` We have our template (a simple form), and our script block. Within the script block, we export an object with three keys: name, computed, and methods. If you are familiar with Vue, this should look familiar to you. Now, let's switch this code to use the Composition API. ` Our component does the exact same thing as before. We define our state (name), a computed property (isNamePresent), and our submit function. If any of this is unfamiliar, check out my previous articles on the Vue Composition API. Rather than having to scaffold our application within an object being exported, we are free to define our variables as we want. This flexibility also allows us to extract repeated logic from the component if we want to, but in this case our component is pretty straightforward. However, we still have that awkward export default statement. Our code all lives within the setup function, while the rest is really just boilerplate. Can't we just remove it? Actually, we can now! This is where comes in. Let's switch to use script setup instead of the standard script block. ` Let's go over what changed here. First, we added the word "setup" to our script tag, which enables this new mode for writing Vue components. Second, we took our code from within the setup function, and replaced our existing exported object with just our code. And everything works as expected! Note that everything declared within the script tags is available in the template of your component. This includes non-reactive variables or constants, as well as utility functions or other libraries. The major benefit of this is that you don't need to manually bind an external file (Constants.js, for example) as a value of your component - Vue handles this for you now. Additional Features You may be wondering how to handle some of the core aspects of writing Vue components, like utilizing other components or defining props. Vue 3.2 has us covered for those use cases as well! Let's take a look at some of the additional features provided by this approach to building Vue single-file components. Defining Components When using , we don't have to manually define our imported components any more. By importing a component into the file, the compiler is able to automatically add it to our application. Let's update our component by abstracting the form into its own component. We'll call it Form.vue. For now, it will simply be the template, and we'll get to the logic in a moment. ` That's it! Our component now has to be imported into our Vue file, and it's automatically available in our template. No more components block taking up space in our file! Now, we need to pass name into our child component as a prop. But wait, we can't define props! We don't have an object to add the props option to! Also, we need to emit that the form was submitted so that we can trigger our submission. How can we define what our child component emits? defineProps and defineEmits We can still define our components props and emits by using new helper methods defineProps and defineEmits. From the Vue docs, "defineProps and defineEmits are compiler macros only usable inside . They do not need to be imported, and are compiled away when is processed." These compile-time functions take the same arguments as the standard keys would use with a full export object. Let's update our app to use defineProps and defineEmits. ` Let's go over what changed here. - First, we used defineProps to expect a modelValue (the expected prop for use with v-model in Vue 3). - We then defined our emits with defineEmits, so that we are both reporting what this component emits, and are also getting access to the emit function (previously available on `this.$emit). - Next, we create a computed property that utilizes a custom getter and setting. We do this so we can easily use v-model on our form input, but it's not a requirement. The getter returns our prop, where the setter emits the update event to our parent component. - Last of all, we hook up our submitHandler function to emit a submit event as well. Our App.vue component is more or less as we left it, with the addition of v-model="name" and @submit="submitForm" to the Form child component. With that, our application is working as expected again! Other Features There are a lot more features available to us here, but they have fewer use cases in a typical application. - Dynamic Components - Since our components are immediately available in the template, we can utilize them when writing a dynamic component (, for example). - Namespaced Components - If you have a number of components imported from the same file, these can be namespaced by using the import * as Form syntax. You then have access to or , for example, without any extra work on your part. - Top-Level Await - If you need to make an API request as part of the setup for a component, you are free to use async/await syntax at the top level of your component - no wrapping in an async function required! Keep in mind that a component that utilizes this must be wrapped externally by a component - read more here to learn how to use Suspense in Vue. Another point to keep in mind is that you aren't locked into using . If you are using this new syntax for a component and run into a case where you aren't able to get something done, or simply want to use the Options syntax for a particular case, you are free to do so by adding an additional block to your component. Vue will mix the two together for you, so your Composition code and Options code can remain separate. This can be extremely useful when using frameworks like Nuxt that provide additional methods to the standard Options syntax that are not exposed in . See the Vue docs for a great example of this. Conclusion This is a big step forward for Vue and the Composition API. In fact, Evan You has gone on the record as saying this is intended to be the standard syntax for Vue single-file components going forward. From a discussion on Github: > There's some history in this because the initial proposal for Composition API indicated the intention to entirely replace Options API with it, and was met with a backlash. Although we did believe that Composition API has the potential to be "the way forward" in the long run, we realized that (1) there were still ergonomics/tooling/design issues to be resolved and (2) a paradigm shift can't be done in one day. We need time and early adopters to validate, try, adopt and experiment around the new paradigm before we can confidently recommend something new to all Vue users. > That essentially led to a "transition period" during which we intentionally avoided declaring Composition API as "the new way" so that we can perform the validation process and build the surrounding tooling /ecosystem with the subset of users who proactively adopted it. > Now that has shipped, along with improvements in IDE tooling support, we believe Composition API has reached a state where it provides superior DX and scalability for most users. But we needed time to get to this point. Earlier in that same thread, Evan expressed his views on what development looks like going forward for Vue: > The current recommended approach is: > - Use SFC + + Composition API > - Use VSCode + Volar (or WebStorm once its support for ships soon) > - Not strictly required for TS, but if applicable, use Vite for build tooling. If you're looking to use Vue 3 for either a new or existing application, I highly recommend trying out this new format for writing Vue single-file components. Looking to try it out? Here's a Stackblitz project using Vite and the example code above....

Implementing Dynamic Types in Docusign Extension Apps cover image

Implementing Dynamic Types in Docusign Extension Apps

Implementing Dynamic Types in Docusign Extension Apps In our previous blog post about Docusign Extension Apps, Advanced Authentication and Onboarding Workflows with Docusign Extension Apps, we touched on how you can extend the OAuth 2 flow to build a more powerful onboarding flow for your Extension Apps. In this blog post, we will continue explaining more advanced patterns in developing Extension Apps. For that reason, we assume at least basic familiarity with how Extension Apps work and ideally some experience developing them. To give a brief recap, Docusign Extension Apps are a powerful way to embed custom logic into Docusign agreement workflows. These apps are lightweight services, typically cloud-hosted, that integrate at specific workflow extension points to perform custom actions, such as data validation, participant input collection, or interaction with third-party services. Each Extension App is configured using a manifest file. This manifest defines metadata such as the app's author, support links, and the list of extension points it uses (these are the locations in the workflow where your app's logic will be executed). The extension points that are relevant for us in the context of this blog post are GetTypeNames and GetTypeDefinitions. These are used by Docusign to retrieve the types supported by the Extension App and their definitions, and to show them in the Maestro UI. In most apps, these types are static and rarely change. However, they don't have to be. They can also be dynamic and change based on certain configurations in the target system that the Extension App is integrating with, or based on the user role assigned to the Maestro administrator on the target system. Static vs. Dynamic Types To explain the difference between static and dynamic types, we'll use the example from our previous blog post, where we integrated with an imaginary task management system called TaskVibe. In the example, our Extension App enabled agreement workflows to communicate with TaskVibe, allowing tasks to be read, created, and updated. Our first approach to implementing the GetTypeNames and GetTypeDefinitions endpoints for the TaskVibe Extension App might look like the following. The GetTypeNames endpoint returns a single record named task: ` Given the type name task, the GetTypeDefinitions endpoint would return the following definition for that type: ` As noted in the Docusign documentation, this endpoint must return a Concerto schema representing the type. For clarity, we've omitted most of the Concerto-specific properties. The above declaration states that we have a task type, and this type has properties that correspond to task fields in TaskVibe, such as record ID, title, description, assignee, and so on. The type definition and its properties, as described above, are static and they never change. A TaskVibe task will always have the same properties, and these are essentially set in stone. Now, imagine a scenario where TaskVibe supports custom properties that are also project-dependent. One project in TaskVibe might follow a typical agile workflow with sprints, and the project manager might want a "Sprint" field in every task within that project. Another project might use a Kanban workflow, where the project manager wants a status field with values like "Backlog," "ToDo," and so on. With static types, we would need to return every possible field from any project as part of the GetTypeDefinitions response, and this introduces new challenges. For example, we might be dealing with hundreds of custom field types, and showing them in the Maestro UI might be too overwhelming for the Maestro administrator. Or we might be returning fields that are simply not usable by the Maestro administrator because they relate to projects the administrator doesn't have access to in TaskVibe. With dynamic types, however, we can support this level of customization. Implementing Dynamic Types When Docusign sends a request to the GetTypeNames endpoint and the types are dynamic, the Extension App has a bit more work than before. As we've mentioned earlier, we can no longer return a generic task type. Instead, we need to look into each of the TaskVibe projects the user has access to, and return the tasks as they are represented under each project, with all the custom fields. (Determining access can usually be done by making a query to a user information endpoint on the target system using the same OAuth 2 token used for other calls.) Once we find the task definitions on TaskVibe, we then need to return them in the response of GetTypeNames, where each type corresponds to a task for the given project. This is a big difference from static types, where we would only return a single, generic task. For example: ` The key point here is that we are now returning one type per task in a TaskVibe project. You can think of this as having a separate class for each type of task, in object-oriented lingo. The type name can be any string you choose, but it needs to be unique in the list, and it needs to contain the minimum information necessary to be able to distinguish it from other task definitions in the list. In our case, we've decided to form the ID by concatenating the string "task_" with the ID of the project on TaskVibe. The implementation of the GetTypeDefinitions endpoint needs to: 1. Extract the project ID from the requested type name. 1. Using the project ID, retrieve the task definition from TaskVibe for that project. This definition specifies which fields are present on the project's tasks, including all custom fields. 1. Once the fields are retrieved, map them to the properties of the Concerto schema. The resulting JSON could look like this (again, many of the Concerto properties have been omitted for clarity): ` Now, type definitions are fully dynamic and project-dependent. Caching of Type Definitions on Docusign Docusign maintains a cache of type definitions after an initial connection. This means that changes made to your integration (particularly when using dynamic types) might not be immediately visible in the Maestro UI. To ensure users see the latest data, it's useful to inform them that they may need to refresh their Docusign connection in the App Center UI if new fields are added to their integrated system (like TaskVibe). As an example, a newly added custom field on a TaskVibe project wouldn't be reflected until this refresh occurs. Conclusion In this blog post, we've explored how to leverage dynamic types within Docusign Extension Apps to create more flexible integrations with external systems. While static types offer simplicity, they can be constraining when working with external systems that offer a high level of customization. We hope that this blog post provides you with some ideas on how you can tackle similar problems in your Extension Apps....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co