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:
- A blocks API key
- A flow identifier and version tag
- A block identifier
Installation
You can install the Vue SDK into your Vue project with a JavaScript package manager:
- npm
- Yarn
- pnpm
npm install @dopt/vue
yarn add @dopt/vue
pnpm add @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'
);
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.
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 Ref
s 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>
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 Ref
s 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 →
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.
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
.
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.
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>
.