Skip to main content

Using the Vue SDK

Overview

This guide will walk you through the tools that the Vue SDK provides and examples on how to use them to build an onboarding experience.

Before we get started, you'll need:

Installation

You can install the Vue SDK into your Vue project with a JavaScript package manager:

npm install @dopt/vue

Usage

The Vue SDK consists of two parts: a plugin (DoptPlugin) and composables.

DoptPlugin

The DoptPlugin allows you to leverage Dopt composables by providing access to the state of component blocks for a given flow version in the context of an identified user.

Here’s what the plugin might look like in your app:

app.use(DoptPlugin, {
apiKey: 'YOUR_BLOCKS_API_KEY',
userId: '0001',
flowVersions: {
'user-onboarding': 2,
upsell: 4,
'feature-callout': 0,
},
});

useBlock composable

The useBlock composable helps you bind block state and content to your UI and also gives you access to methods for mutating block state.

Here’s how using the composable might look like in your app for the twenty-llamas-attack block in the new-user-onboarding flow:

const block = useBlock<['complete']>(
'new-user-onboarding.twenty-llamas-attack'
);
info

The <['complete']> portion in the useBlock instantiation is a TypeScript specific concept which allows you to enumerate the transitions associated with the block. This provides a bunch of utility in terms of error detection and code completion while developing with the SDK.

info

The example above uses the block identifier (twenty-llamas-attack) prefixed with the flow identifier (new-user-onboarding). However, you can also use the uid for the block without the flow identifier prefix instead.

You can destructure the block variables to expose a subset of block data:

const { state, transitioned, field, transition } = useBlock<['complete']>(
'new-user-onboarding.twenty-llamas-attack'
);

This is often useful when relying Refs returned by the useBlock composable. For example, because state is a Ref<{ active: boolean; entered: boolean; exited: boolean; }>, you can use it directly within a template:

<template>
<div v-if="state.active">Hello world!</div>
</template>
info

Wherever possible, useBlock and other composables will return Ref wrappers of primitives (like version or uid) or objects (like state or transitioned). Otherwise, composables will return functions like field and transition.

useFlow composable

The useFlow composable helps you bind flow state to your UI and also gives you access to methods for mutating flow state.

Here’s how using the composable might look like in your app for the new-user-onboarding flow:

const flow = useFlow('new-user-onboarding');

You can further destructure the flow and intent variables to expose a subset of flow Refs and intent methods:

const { state, version, finish, reset } = useFlow('new-user-onboarding');

Example

Let’s walk through an example of how you might use the Vue SDK to build an onboarding experience.

Initializing DoptPlugin

First, we’ll need to initialize the DoptPlugin in our app.

import { DoptPlugin } from '@dopt/vue';
import Application from './Application.vue';

const app = createApp(App);

app.use(DoptPlugin, {
apiKey: 'YOUR_BLOCKS_API_KEY',
userId: '0001',
flowVersions: {
'new-user-onboarding': 2,
},
});

app.mount('#root');

We’ve hardcoded the user identifier (0001) for demonstration purposes in the userId prop. Realistically, you should dynamically pass in the user identifier that you used to identify the user who will be seeing this onboarding experience.

We’ve added our blocks API key to the apiKey prop.

And finally, we’ve defined that we want to pull in version 2 of the new-user-onboarding flow in the flowVersions prop. Learn more about flow versioning →

info

If you’d like to pull in the uncommitted version of a flow, you can set the version tag to "uncommitted" or 0. This can help while you’re actively developing a flow.

info

If your user’s identifier isn’t ready yet, for example, because an async dependency hasn’t finished fetching, you can pass in userId: undefined, and Dopt's composables will return sensible defaults. You can subsequently use the useUpdateUser composable to let Dopt know that your user is ready, and Dopt will update and trigger all composables with updated flow and block values.

Reacting to block state

Now that we’ve added DoptPlugin to our app, we can use the useBlock composable to bind our UI to block state.

Let’s walk through an example of conditionally rendering a modal based off of the active state of a custom component block. Basically, this boils down to showing the modal when the custom component block active state is true and hiding it when the active state is false.

info

This example showcases reacting to the active block state, but you can hook up your UI to the entered and exited states as well.

The useBlock composable helps us access the active state:

<script>
import { useBlock } from '@dopt/vue';
import { Modal } from './modal';
const { state } = useBlock<['complete']>(
'new-user-onboarding.twenty-llamas-attack'
);
</script>
<template>
<Modal v-if="state.active">
<h1>👏 Welcome to our app!</h1>
<p>This is your onboarding experience!</p>
</Modal>
</template>

We’ve pulled in the state of the twenty-llamas-attack custom component block. The <Modal /> is then set to conditionally render if state.active evaluates to true.

Mutating block state

Now that we’ve bound our modal to Vue to block state, let’s also set it up so that clicking a button hides the modal. Imagine that we’ve created a path named complete from the twenty-llamas-attack custom component block to the next block in our flow.

Let’s build off of our previous code using the useBlock composable:

<script>
import { useBlock } from '@dopt/vue';
import { Modal } from './modal';
const { state, transition } = useBlock<['complete']>(
'new-user-onboarding.twenty-llamas-attack'
);
</script>
<template>
<Modal v-if="state.active">
<h1>👏 Welcome to our app!</h1>
<p>This is your onboarding experience!</p>
<button v-on:click="() => transition('complete')">Close me</button>
</Modal>
</template>

We’ve made two changes to the original example. First, we're pulling in the transition() function from the useBlock composable. This allows us to transition the twenty-llamas-attack custom component block along it’s complete path which in turn will also update the block’s state to active: false and exited: true.

Second, we’ve added a <button /> with an @click handler that calls the transition() function. Within the transition() function, we are passing in our complete path name to indicate that the user should transition along the complete path. This translates to a click on the button setting the active state to false which will hide our modal.

info

Calling transition('complete') will also update the block’s transitioned data to { complete: true } to reflect that the block was transitioned along its complete path.

Using fields

Pulling down field values is just as easy as using state. Let's imagine that we have configured text fields for a title, body, and button for our modal. We can access these fields using the field() accessor from the useBlock composable.

<script>
import { useBlock } from '@dopt/vue';
import { Modal } from './modal';
const { state, field, transition } = useBlock<['complete']>(
'new-user-onboarding.twenty-llamas-attack'
);
</script>
<template>
<Modal v-if="state.active">
<h1>{{ field('title') }}</h1>
<p>{{ field('body') }}</p>
<button v-on:click="() => transition('complete')">
{{ field('button') }}
</button>
</Modal>
</template>

Note how we've replaced all of the static content with field() that references the field's identifier. When this modal renders, the field values that we define in Dopt will show up for in the <h1>, <p>, and <button>.