Overview
This how-to guide details how to create a custom (Bring Your Own) Task List component. It demonstrates how to build an asset that fully integrates with the Unqork platform using its own event and operation.
The Bring Your Own feature is intended for developers who have a strong understanding of the Unqork Designer Platform and JavaScript.
BYO Task List Asset Ideation
For this example, the fictional client company "ABC" wants to implement a Task List as a custom component in the Unqork Designer Platform. The component itself should let Creators configure the task list's Express View title, add or remove additional items, and add the option to set items to completed (checked). The client requests the Task List to support an event that emits when a user clicks on an item in the checklist. They also ask that it include an operation that sets the completed (checked/unchecked) state of a single item in the checklist.
As the developer assigned to this task, break down and document the client's ask into actionable sections:
Asset Types: What types of assets are needed to implement to meet the client's requirements of a Task List asset?
Component(s): Does the client's request require the creation of something not currently supported in the Unqork platform?
Event(s): Does the asset need to emit an event when it's used? What action should emit the event?
Operation(s): Does the asset need to be manipulated by other elements using an operation?
Inputs & Outputs: Catalog a list of potential inputs and outputs for the asset. Events are typically an output in this list.
Naming Scheme: Create a naming scheme for the asset that does not conflict with Unqork values, or potential future custom assets.
To understand naming scheme limitations, view the Important callout in the overview of our Bring Your Own (BYO): Understanding the manifest.json File article.
Now that the client has described the ask, create a document detailing all the potential elements the Task List asset requires.
Example Ideation Documentation
The sections below detail the product requirements that meet the client's request. Developers use this information to implement the component’s JavaScript, create the manifest file and package, and package it to the Unqork Designer Platform.
Component(s)
A custom Unqork component that imports an AG Grid data table.
Component Name | Description |
---|---|
Task List | A simple list of items with check boxes next to each. End-users click on each item to check or uncheck the item in the list. |
Event(s)
An event used as part of the Events & Operations Builder.
Parameter | Object Type | Description |
---|---|---|
Task List Item Toggled |
| An event that emits when an end-user checks or unchecks a task item. The event includes a payload with the text and completed status of the updated item. Event Payload: Adds the name of the item that was clicked. |
Operation(s)
An operation used as part of the Events & Operations Builder.
Parameter | Object Type | Description |
---|---|---|
Task List Toggle Task List Item |
| Toggles or explicitly sets the completed state of a single item in a target task list. Includes the following settings:
|
Input(s)
Creators use the input fields to map and label columns.
Parameter | Object Type | Description |
---|---|---|
| string componentKey | The title that displays above the task list. Default value is "Tasks". |
| string componentKey | An array of objects that defines the task items in the list. Each object in the array contains the following:
|
Libraries
No libraries are required for this component.
Library Name | Description | Documentation Link |
---|---|---|
N/A | N/A | N/A |
Naming Scheme
Verify that all naming values do not conflict with existing Unqork assets or other custom assets in the environment.
IMPORTANT
Unqork does not enforce programmatic name spacing for custom asset types. All type values for components, operations, and events must be globally unique. If multiple custom assets share the same type, or if a custom asset uses a type that conflicts with a native Unqork type, the runtime will render or execute only the first matching definition. Doing so leads to unpredictable behavior, asset shadowing, or broken functionality—especially when bundling or importing multiple packages.
It is the responsibility of the developer to ensure type uniqueness to prevent collisions. Component, operation, and event types require a unique name to avoid collision issues.
To avoid namespace issues, prefix custom components with a name unique to your company or application. For example, if a company named ABC creates a Card Panel component. The component's name space could be
abcCardPanel
.
Asset Type | Asset Name | Naming Scheme |
---|---|---|
Component | Task List |
|
Event / Output | Task List Item Toggled |
|
Input | Label |
|
Input | Task Item Name and Boolean Value |
|
Create the manifest.json
File
The manfest.json file serves as the contract between Unqork and the Task List implementation.
{
"name": "TaskList",
"version": "1.0.0",
"main": "taskList.js",
"type": "custom",
"productType": "BYO",
"description": "A simple task list component with an event and an operation.",
"components": [
{
"name": "Example Task List",
"type": "taskList",
"description": "Simple task list with checkboxes.",
"model": {
"type": "object",
"properties": {
"label": {
"name": "Label",
"type": "string",
"description": "Label of Task List",
"default": "Tasks"
},
"value": {
"name": "Value",
"type": "array",
"description": "Array of task items",
"items": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Text to display for the task item"
},
"completed": {
"type": "boolean",
"description": "Whether the item is completed",
"default": false
}
},
"required": ["text"]
},
"default": []
}
},
"required": ["value"]
},
"events": [
{
"name": "Example Task List Item Toggled",
"type": "taskListItemToggled",
"description": "Emitted when an end-user checks/unchecks a task item.",
"stability": "STABLE",
"model": {
"type": "object",
"properties": {
"name": {
"const": "taskListItemToggled",
"type": "string",
"description": "Name of the event"
},
"payload": {
"type": "object",
"description": "The event payload.",
"properties": {
"item": {
"type": "object",
"description": "A task list item.",
"properties": {
"text": { "type": "string", "description": "Task name."},
"completed": { "type": "boolean", "description": "Whether this task is completed."}
}
}
},
"required": [
"item"
]
}
}
}
}
],
"operations": [
{
"name": "Example Task List Toggle Task List Item",
"type": "toggleTaskListItem",
"description": "Toggle (or set) the completion state of a specific item on a target task list.",
"stability": "STABLE",
"model": {
"type": "object",
"properties": {
"options": {
"type": "object",
"properties": {
"targetKey": {
"name": "Target Key",
"type": "string",
"description": "Component key of the task list to modify"
},
"item": {
"name": "Item",
"description": "Index (number) or text (string) of the item to change",
"type": ["number", "string"]
},
"completed": {
"name": "Completed",
"type": "boolean",
"description": "Optional explicit completed value; if omitted, the value is toggled"
}
}
},
"type": {
"const": "toggleTaskListItem",
"type": "string"
}
},
"required": ["targetKey", "item"]
}
}
]
}
]
}
The following fields are used at the root level of the manifest:
Field | Type | Required | Description |
---|---|---|---|
| string | A unique identifier for the package. For example, | |
| string | The semantic version number. For example, | |
| enum | The package type. Currently, the only supported value is | |
| enum | The target platform feature. Currently, the only supported value is | |
| string | A description that displays in the Admin Panel after installation. | |
| string | The relative path to the JavaScript entry file. For example, | |
| array<component-description> | Optional | A list of component definitions included in the package. |
| array<event-description> | Optional | List of event definitions. |
| array<operation-description> | Optional | List of operation definitions. |
Understanding the components[] Definition
This definition defines the Task List component:
Export | Description | |
---|---|---|
| Define the component's name and its internal identifier. The | |
| This object defines a custom event. It exports a model that describes the structure of the event's payload ( | |
↳ |
| A string property that serves as the title for the task list. |
| An array property that contains the list of task items. Each item is an object with a text (string) and completed (boolean) property. This schema ensures that the data passed to the component is always in the correct format. | |
| This section defines the events the component can emit. | |
↳ |
| The human-readable name and the unique identifier of the |
| Explains when the event is emitted. | |
| A schema that defines the payload of the event, ensuring that the data sent with the event ( | |
| This section defines the actions or operations that can be performed on the component from outside. | |
↳ |
| The name and unique identifier of the |
| Explains what the operation does. | |
| Defines the options or parameters for the operation. It requires a |
To learn more about the manifest.json file, view the following topic: Understanding the manifest.json File
Implement the Task List
For this example, create a file called taskList.js
. In this file, create a Web Component that does the following:
Creates a Shadow DOM as a part of the BYO implementation requirements.
Initializes the Unqork Runtime API as a part of the BYO implementation requirements.
Subscribes to state changes so that the component can look for changes to the
label
orvalue
property, updating the rendering to match. Changes to these properties are made using configuration in the Module Builder.Converts data into a standardized array of objects. Doing so improves error handling if the data is given as a string instead of an array.
Emits an event back to the Unqork runtime, so configuration can use the event with Operations Builder to trigger downstream logic.
Renders the Task List in Express View as HTML.
Review the code example below for more information on each method:
NOTE
The comments in the JavaScript below are written in the JSDoc format. For more information on JSDoc block tags (@param, @return), visit the JSDoc website: https://jsdoc.app/.
class UnqorkTaskListComponent extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
this.items = []
this.label = 'Tasks'
}
/**
* This is the only required method to integrate with the Unqork system
*
* @param {*} api The interface to the Unqork Runtime, used for both
* monitoring state and emitting events
*/
initialize(api) {
this.api = api
this.config = api.state.currentState()
// Initial label and value from config (if provided)
if (this.config.label != null) this.label = String(this.config.label)
if (this.config.value != null) this.items = this._normalizeItems(this.config.value)
// Method to render component in the DOM.
this.render(this.shadowRoot, this.label, this.items)
// Subscribe to state changes such as SET_PROPERTY
this.subscribeLabel()
this.subscribeValue()
}
/**
* Subscribes to changes in the `label` property of the component's state.
*
* This method listens to the `state$('label')` observable for updates to the `label` property.
* When a new value is emitted, it updates the `label` property of the component and re-renders the component.
*
* @returns {void}
*/
subscribeLabel() {
this.api.state.state$('label').subscribe((label) => {
this.label = label ?? ''
this.shadowRoot.innerHTML = this.view(this.label, this.items)
})
}
/**
* Subscribes to changes in the `value` property of the component's state.
*
* This method listens to the `state$('value')` observable for updates to the `value` property.
* When a new value is emitted, it normalizes the value into an array of items and updates the `items` property.
* It then re-renders the component with the updated items.
*
* @returns {void}
*/
subscribeValue() {
this.api.state.state$('value').subscribe((value) => {
this.items = this._normalizeItems(value)
this.shadowRoot.innerHTML = this.view(this.label, this.items)
})
}
/**
* Normalizes the input value into an array of objects with a specific structure.
*
* This method ensures that the input `value` is converted into an array of objects,
* where each object contains the following properties:
* - text: The text to actually display in the taskList item (defaults to an empty string if missing).
* - completed: A boolean indicating whether the item is completed (defaults to `false` if missing).
*
* @param value - The input value to normalize. Can be a JSON string or an array.
* @returns The normalized array of items.
*/
_normalizeItems(value) {
const arr = typeof value === 'string' ? JSON.parse(value) : value
if (!Array.isArray(arr)) return []
return arr.map((item) => ({
text: String(item?.text ?? ''),
completed: Boolean(item?.completed),
}))
}
render(root, label, items) {
root.innerHTML = this.view(label, items)
root.addEventListener('change', (ev) => {
const el = ev.target
if (!(el instanceof HTMLInputElement) || el.type !== 'checkbox') return
const idx = Number(el.getAttribute('data-index'))
if (Number.isNaN(idx) || !this.items[idx]) return
const updatedItem = { ...this.items[idx], completed: el.checked }
const next = [...this.items]
next[idx] = updatedItem
// Update state with new item value
this.api.state.set({ value: next })
// Emit taskListItemToggled event
this.emitItemToggledEvent(updatedItem)
})
}
/**
* Emits a `taskListItemToggled` event when a to-do list item is toggled.
*
* This method triggers a domain event with the name `taskListItemToggled` and includes
* the toggled item's details in the event payload. The payload contains the updated item
* with its `text` and `completed` properties.
*
*/
emitItemToggledEvent = (item) => {
this.api.events.emit({
name: 'taskListItemToggled',
payload: { item },
})
}
// The component view
view(label, items) {
const list = items
.map(
(item, i) => `
<li>
<label>
<input type="checkbox" data-index="${i}" ${item.completed ? 'checked' : ''} />
${item.text}
</label>
</li>`,
)
.join('')
return `
<div>${label ?? ''}</div>
<ul data-role="list">
${list}
</ul>
`
}
}
/**
* This definition defines the state settings (model) for this component
* It mirrors the fuller description in manifest.json and will
* eventually be used to auto-generate the manifest.json schema
*/
class TaskListDefinition {
label
value
}
/**
* This export provides the view and model definitions for the component,
* which are utilized by the Unqork Runtime for configuration and execution.
* Both definitions are `async` to enable on-demand loading, improving initial page load performance.
*
* Component export name MUST match manifest `type`
*/
export const taskList = {
model: async () => TaskListDefinition,
view: async () => UnqorkTaskListComponent,
}
/** ========= Example Task List Item Toggled Event Model ========= **/
// Defines the structure of the payload for the taskListItemToggled event
class TaskListItemToggledPayload {
item = { text: '', completed: false }
}
// This definition describes the schema of the event that is emitted
// when the user toggles an item
class TaskListItemToggled {
// The name of the event
name = 'taskListItemToggled'
// The details of the toggled to-do list item
payload = new TaskListItemToggledPayload()
}
// This export is used to expose the event to the Unqork Runtime
// Note: event export name MUST match manifest `type`
export const taskListItemToggled = {
model: async () => TaskListItemToggled,
}
/** ======== Example Task List Toggle Task List Item Operation ======== **/
// Operation options/schema for toggling a task list item
class ToggleTaskListItemOptions {
// key of the taskList component to modify
targetKey
// number (index) OR string (text) of the item to change
item
// Boolean to set completed property of item to. If not provided, just toggle the existing value (e.g. true -> false and false -> true)
completed
}
class ToggleTaskListItemOperation {
// MUST match the manifest "type" and the named export below
type = 'toggleTaskListItem'
options = new ToggleTaskListItemOptions()
}
class ToggleTaskListItemHandler {
/**
* Execute the operation.
* @param {ToggleTaskListItemOperation} operation
* @param {*} api Operation API: { state: { resolveByKey, set, get }, events: { emit } }
*/
async execute(operation, api) {
const { targetKey, item, completed } = operation.options.config || {}
if (!targetKey) throw new Error('toggleTaskListItem Operation: "targetKey" is required.')
if (item === undefined || item === null)
throw new Error('toggleTaskListItem Operation: "item" (index or text) is required.')
// Resolve the target component state
const target = api.state.resolveByKey(targetKey)
// Expecting a list of items like the following:
// [
// { "text": "Buy groceries", "completed": false },
// { "text": "Complete design doc", "completed": true }
// ]
const list = target?.value ?? []
if (!Array.isArray(list)) throw new Error('toggleTaskListItem Operation: target value is not an array.')
// Find the target index
let index = typeof item === 'number' ? item : list.findIndex((it) => String(it?.text ?? '') === String(item))
// Ensure the index is within bounds, otherwise throw an error
if (index < 0 || index >= list.length) {
throw new Error(`toggleTaskListItem Operation: could not find item "${item}".`)
}
// Get the current item or default to an empty object with default properties
const current = list[index] ?? { text: '', completed: false }
// Determine the next completion state based on the provided `completed` boolean or toggle the current state
const nextCompleted = typeof completed === 'boolean' ? completed : !current.completed
// Create a new list with the updated item at the specified index
const newList = [...list]
newList[index] = { ...current, completed: nextCompleted }
// Update the target component state with the new list
api.state.set(targetKey, { value: newList })
}
}
// The following class is omitted since the operation handler does not return a result
// class ToggleTaskListItemContext {
// ...
// }
// Named export — MUST match manifest "type"
export const toggleTaskListItem = {
model: async () => ToggleTaskListItemOperation,
handler: async () => ToggleTaskListItemHandler,
//This is omitted since the operation handler does not return a result
//contextModel: async () => ToggleTaskListItemContext,
}
Understanding the UnqorkTaskListComponent
Class and its Methods
The UnqorkTaskListComponent
class Web Component is the core of the Task List BYO component. Learn more about each of its methods below:
Method | Description |
---|---|
| This method runs when the component is created. It sets up a Shadow DOM ( |
| This is the most crucial method for Unqork integration. The Unqork runtime calls this method to give the component access to the |
| These methods demonstrate how the component subscribes to state changes. They use Unqork's |
| This is a private helper method that ensures the data is in the correct format. It takes a raw value (which could be a JSON string or an array) and converts it into a clean, standardized array of objects with |
| This method handles rendering the component and adding event listeners. It takes the component's internal data ( |
| This method uses the |
| This method is a pure function that generates the component's HTML markup. It takes the label and items data and uses JavaScript's |
Understanding the taskList
and taskListItemToggled
Exports
These exports act as the component's manifest, providing the Unqork runtime with the necessary data to use the component.
Export | Description |
---|---|
| This object exports the |
| This object defines a custom event. It exports a |
Understanding the ToggleTaskListItemHandler
Class and toggleTaskListItem
Export
This section defines a custom Unqork operation, which is a server-side action that can be executed from a workflow or other part of the Unqork application.
Export | Description |
---|---|
| This class contains the
|
| This object exports the |
To learn more about implementing assets, view the following resources:
Custom Component SDK: Extend component functionality in the Unqork Designer Platform.
Custom Component: Understand the state, interface, and events of a custom component.
Custom Events: Learn more about creating custom events for use in the Operations Builder.
Custom Operations: Learn more about creating custom operations for use in the Operations Builder.
Create the BYO Task List Package
After the asset JavaScript and manifest.json files are complete, compress them into a BYO package.
To compile a file using Terminal (Mac) or Command Prompt (Windows):
Using the command line prompt, navigate to the directory containing the
taskList.js
andmanifest.json
files. For example,cd C:\Users\UserName\Desktop\taskListAsset
.Execute the following command:
tar -cvzf taskList.tar.gz manifest.json taskList.js
.The
taskList.js
file andmanifest.json
are added to thetar.gz
file in the same folder they're located in.NOTE
The steps above use the
tar
command and the following options:-c
: Creates a new archive.-z
: Compresses the archive using gzip.-v
: Lists the files in the command line as they are added to archive.-f
: Specifies the file name for the archived files.
Learn more about BYO Packages using the following resource: Create a BYO Package
Upload the BYO Task List Package
After creating the taskList.tar.gz
package, upload it to the Unqork Designer Platform using the Custom Assets Administration page:
From the UDesigner homepage, click Administration.
Under Assets, click Custom Assets Administration.
Click + Create new. The Create Asset modal displays.
Under File Upload, click or drag a BYO package from your local device to the upload window.
Click Scan File. The package details display.
NOTE
If an import error occurs, review the package's contents for errors and name mismatches.
Click Review Assets.
Review the asset's details including Components, Events, and Operations.
Click Confirm & Create.
Review the Library Usage Acknowledgment and Liability Agreement. Click the ☐ (checkbox) to acknowledge the agreement.
Click Create Asset.
The asset package displays in the Custom Asset's Packages list. The package's individual assets display in the Assets tab's Assets list. The assets are now available in the Module Builder for all applications in the environment.
Learn more about the Custom Assets Administration page using the following resource: Custom Assets Administration
Test the Task List Component
Now that the BYO Task List component is in the Unqork Designer Platform, test its functionality in the Module Builder and Express View. This example assumes you are configuring a Vega (v2.0) module.
For this example, test the following functions:
Task List Configuration Drawer: Verify each setting is functional.
taskListItemToggledEvent
Event: Verify the event emits when clicking a task list item.toggleTaskListItem
Operation: Verify the operation accepts the following keys and values:targetKey
(task list property ID),item
(task list item), andcompleted
(Checked/Unchecked).
Configure the Custom Component
The Custom Component contains a list of all BYO components in the environment. Select the Example Task List, then configure it to test settings, events, and operations.
In the Module Builder, drag and drop a Custom Component onto your canvas.
In the Property ID field, enter
byoTaskList
.From the Select Component drop-down, enter or select
Example Task List
. The component's configuration populates.Under Object 1, in the text field, enter
First Item
.Set Object 1 to
(Completed).
Under Object 2, in the text field, enter
Second Item
.Under Object 3, in the text field, enter
Third Item
.
Configure the byoTaskList Events and Operations
While remaining in the configuration drawer, set up the BYO event taskListItemToggled
to hide a button by setting its display.hidden
property to false.
Navigate to the Actions settings.
Next to Events & Operations, click Edit. The Events & Operations modal displays.
From the Select an Event drop-down, enter or select
Example Task List Item Toggle
. This custom event was imported as part of the BYO Task List package.Click Add.
Click +Add Operation.
From the Operation Type drop-down, select
Set Property
.In the Target Key field, enter
btnCheckSecondItem
. You'll set thebtnCheckSecondItem
Button component Icon Button component in the next section.In the Property ID field, enter
display.hidden
. This value targets the Button component's hidden key, which controls the visibility of the button.In the Value field, enter
false
. This value hides the button when the operation triggers.Click Save.
Click Close.
Click Save Component.
Configure the Button Component
Configure a Button component to emit an On Click event. Configure the event to trigger the BYO toggleTaskListItem operation . When this operation triggers, it checks the second item in the task list.
Drag and drop a Button component Icon Button component onto your canvas, placing it above the byoTaskList
Custom Component.
In the Property ID field, enter
btnCheckSecondItem
.In the Label Text field, enter
Check Second Item
.Navigate to the Actions settings.
From the Action Type drop-down, select
Event
.Next to Events & Operations, click Edit. The Events & Operations modal displays.
From the Select an Event drop-down, enter or select
On Click
. This event emits when the user clicks the button.Click Add.
Click +Add Operation.
From the Operation Type drop-down, select
Example Task List Toggle Task List Item
. This custom operation was imported as part of the BYO Task List package.In the Config field, enter the following JSON code:
{"targetKey":"byoTaskList","item":"Second Item","completed":true}
. This value checks the byoTaskList Custom Component's second item in the list.Click Save.
Click Close.
Click Save Component.
Save your module.
Your completed module looks like the following:
Preview and Test the Module
Preview your module in Express View. Check for the following functionality:
On module load, the list's First Item is set to
(checked). Doing so verifies the
byoTaskList
Custom Component's configuration setting Completed is functioning.Click the Check Second Item button, the list's Second Item sets to
(checked). This verifies the
toggleTaskListItem
operation is functioning.Click any item in the list, the Check Second Item button disappears. This verifies the
taskListItemToggled
event is functioning.
If the custom asset functions as intended, then its ready to be used by Creators in the development of Unqork applications.
If the Custom Component generates errors, or is missing features:
1. Create a copy of the current package and its contents.
2. Update the package's required files.
3. Change the package's version number.
4. Update the package by referring to the Package Management section in our BYO Best Practices article: BYO Best Practices - Package Management