---
title: Custom workflow templates
description: The end-user UI is not bundled with PingIDM. Learn more in Install the end-user UI.
component: pingidm
version: 8.1
page_id: pingidm:workflow-guide:custom-workflow-template
canonical_url: https://docs.pingidentity.com/pingidm/8.1/workflow-guide/custom-workflow-template.html
keywords: ["Workflows", "Custom Templates", "Flowable", "Vue JS Framework"]
section_ids:
  vue3-workflow-migration: Update custom workflow templates for Vue 3
  vue3-workflow-sample-reference: Updated workflow sample
  vue3-workflow-overview-changes: Overview of changes
  vue3-workflow-validation-changes: ValidationObserver and ValidationProvider removal
  vue3-workflow-template-changes: Template syntax changes
  vue3-workflow-slot-syntax: Slot syntax
  vue3-workflow-reactivity-changes: Reactivity changes
  vue3-workflow-localization: Localization keys
---

# Custom workflow templates

|   |                                                                                                                           |
| - | ------------------------------------------------------------------------------------------------------------------------- |
|   | The end-user UI is not bundled with PingIDM. Learn more in [Install the end-user UI](../setup-guide/idm-enduser-ui.html). |

The embedded workflow engine integrates with the default end-user UI. For simple custom workflows, you can use the standard Flowable form properties and have the UI render the corresponding generic forms automatically. For more complex functionality, including input validation, rich input field types, complex CSS, and more, you must define a custom form template.

The default workflows provided with IDM use the [Vue JS framework](https://vuejs.org/guide/introduction.html) for display in the end-user UI. To write a custom form template, you must have a basic understanding of the Vue JS framework and how to create components. A sample workflow template is provided at `/path/to/samples/provisioning-with-workflow/workflow/contractorOnboarding.bar`. To extract the archive, run the following command:

```
jar -xvf contractorOnboarding.bar
inflated: contractorForm.js
inflated: contractorOnboarding.bpmn20.xml
```

The archive includes the workflow definition `contractorOnboarding.bpmn20.xml` and the corresponding JavaScript template `contractorForm.js` to render the workflow in the UI.

## Update custom workflow templates for Vue 3

The end-user UI has been upgraded from Vue 2 to Vue 3. If you have custom workflow form templates written for Vue 2, you must update them to work with Vue 3.

|   |                                                                                                                |
| - | -------------------------------------------------------------------------------------------------------------- |
|   | For in-depth Vue 3 migration guidance, check out the [Vue 3 Migration Guide](https://v3-migration.vuejs.org/). |

### Updated workflow sample

The sample workflow template provided at `samples/provisioning-with-workflow/workflow/contractorOnboarding.bar` has been updated to work with Vue 3. Use this as a reference when updating your own custom workflow form templates.

### Overview of changes

The following changes are specific to custom workflow form templates when moving from Vue 2 to Vue 3.

#### `ValidationObserver` and `ValidationProvider` removal

`ValidationObserver` and `ValidationProvider` from the `vee-validate` library were previously registered as global components by the end-user UI. They are no longer available in Vue 3.

Remove all `ValidationObserver` and `ValidationProvider` elements and replace them with component-local validation. The general pattern is:

1. Add an `errors` object to your component's `data` to track field-level error messages.

2. Replace the `ValidationObserver` ref-based `validate()` call in `submit()` with a synchronous `validateForm()` method that iterates over your form properties.

3. Implement a `validateField()` method that uses the native [`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checkValidity) API to validate individual inputs. For fields that require custom format checking (such as telephone numbers), apply a regex check before calling `checkValidity()`.

4. Replace `getValidationState()` with a `getFieldState()` method that maps the `errors` object state to a boolean: `null` (untouched), `true` (valid), or `false` (invalid).

5. In `resetForm()`, clear the `errors` object alongside resetting the form data so fields return to the untouched state.

#### Template syntax changes

Update the HTML template string in your custom workflow form to reflect the following changes:

* Remove `<ValidationObserver>` and `<ValidationProvider>` wrapper elements.

* Add the `novalidate` attribute to the `<b-form>` element because you're handling validation in JavaScript.

* Replace the static `type="text"` attribute with a dynamic `:type` binding that returns the appropriate HTML5 input type (`email`, `tel`, `date`, and so on) based on the field ID.

* Add `:required="formProperty.required"` to bind the HTML `required` attribute directly.

* Replace `:state="getValidationState(validationContext)"` with `:state="getFieldState(formProperty._id)"`.

* Add `@blur="validateField(formProperty)"` to trigger validation when the user leaves a field.

* Replace `<b-form-invalid-feedback>{{ validationContext.errors[0] }}</b-form-invalid-feedback>` with `<b-form-invalid-feedback v-if="errors[formProperty._id]">{{ errors[formProperty._id] }}</b-form-invalid-feedback>`.

#### Slot syntax

Update the deprecated `slot` attribute syntax to the Vue 3 shorthand:

* Vue 2 (before)

* Vue 3 (after)

```html
<template slot="label">...</template>
```

```html
<template #label>...</template>
```

#### Reactivity changes

Vue 3 uses a proxy-based reactivity system. Replace any calls to `this.$set()` with direct property assignment:

* Vue 2 (before)

* Vue 3 (after)

```javascript
this.$set(this.formData, 'requestApproved', null);
```

```javascript
this.formData.requestApproved = null;
```

#### Localization keys

Do not rely on localization keys from the end-user UI (such as `$t('pages.profile.editProfile.optional')`) in your custom workflow templates. The UI does not guarantee the stability of its internal localization keys, and they could change between releases. Instead, use hardcoded strings or provide your own localization mechanism in your custom form template.
