---
title: Widget Code Structure
slug: widget-code-structure
docTags: 
createdAt: 2025-08-11T11:13:49.000Z
---

Widgets are implemented as anonymous classes that extend the HTMLElement class. The preferred approach is to extend SwimlaneElement, which itself extends LitElement and provides additional functionality for building rich, interactive record and report widgets in Turbine.

## Default Widget Example

Here is an example of the default widget with annotation added:

:::BlockQuote
/\*\*
&#x20;\* Import \`SwimlaneElement\` class.
&#x20;\* The \`css\`, \`html\`, and \`svg\` methods are also imported from \`swimlane-element\`.
&#x20;\*/
import \{ SwimlaneElement, css, html, svg } from '@swimlane/swimlane-element\@2';/\*\*
&#x20;\* The \`recordFrameTemplate\` is a template helper function. See templates below.
&#x20;\*/
import \{ recordFrameTemplate } from '@swimlane/swimlane-element\@2/lib/templates.js';/\*\*
&#x20;\* A Swimlane widget is implemented as an anonymous class which extends the \`SwimlaneElement\` class.
&#x20;\*/
export default class extends SwimlaneElement \{
&#x20; /\*\*
&#x20;  \* The \`styles()\` getter is a static class getter. It defines styles common to all widget instances.
&#x20;  \* This method does not have access to instance-specific properties like \`record\` or \`report\`.
&#x20;  \*/
&#x20; static get styles() \{
&#x20;   return \[super.styles, css\`
&#x20;     .frame\::after \{
&#x20;       content: "Record Output";
&#x20;     }
&#x20;   \`];
&#x20; }  /\*\*
&#x20;  \* The \`render()\` method is an instance method scheduled by \`LitElement\` lifecycle events.
&#x20;  \* It must return a \`lit-html\` template. This method has access to \`this.record\` and \`this.report\`.
&#x20;  \*/
&#x20; render() \{
&#x20;   return recordFrameTemplate(html\`
&#x20;     \<pre>$\{JSON.stringify(this.record, undefined, 2)}\</pre>
&#x20;   \`);
&#x20; }
}
:::

## Properties

SwimlaneElement defines the following properties:

- **this.record** – Available to record widgets. An object containing key-value pairs for each field on the record.
- **this.report** – Available to report widgets. An object with:
  - data: parsed result rows
  - rawData: unprocessed backend response
  - query: the report query
- **this.contextData** – Available to all widgets. Contains contextual information:
  - application
  - currentUser
  - origin
  - token

Documentation on how `LitElement` handles properties and attributes can be found [here](https://lit-element.polymer-project.org/guide/properties).

## Lifecycle

In addition to standard HTMLElement and LitElement lifecycle methods, SwimlaneElement includes:

- **resizedCallback()** – Called when the widget is resized. By default, it calls requestUpdate() to trigger re-rendering.

Documentation of `LitElement` lifecycle methods and properties can be found [here](https://lit-element.polymer-project.org/guide/lifecycle).

## Events

Swimlane widgets can emit platform events using the following methods:

- **this.updateRecordValue(key, value):&#x20;**&#x55;pdates a specific record field by key.
- **this.addComment(comment):** Adds a comment to the record.
  This method returns a Promise, allowing follow-up actions to be chained:
  `this.triggerButton();`
  `}).catch(error => {`
  `console.error("Failed to add comment:", error);`
  `});`
- **this.triggerButton(buttonId):&#x20;**&#x54;riggers a playbook button by its ID.
- **this.triggerSave():&#x20;**&#x53;aves the current record.
  This method also returns a Promise, enabling safe sequencing of actions:
  `this.triggerSave().then(() => {`
  `this.triggerButton();`
  `}).catch(error => {`
  `console.error("Save failed:", error);`
  `});`

:::hint{type="warning"}
Avoid using **setTimeout()** to delay follow-up actions. Use Promises to ensure actions happen after the save or comment completes successfully.
:::

You can also perform multiple asynchronous actions in parallel using `Promise.all()`:

:::BlockQuote
Promise.all(\[
&#x20; this.triggerSave(),
&#x20; this.addComment("Escalated to Tier 2")
]).then(() => \{
&#x20; this.triggerButton();
});
:::

Documentation on how to handle events in `LitElement` can be found [here](https://lit-element.polymer-project.org/guide/events).

## Value Emission Patterns

For single value fields (text/numeric/date fields, etc.) or single-select field types, simply emit the new value:

:::BlockQuote
// value can be a string or number type
this.updateRecordValue('field-key', 'new value');
:::

For text and numeric list field types, emit an array of new values. If duplicate values exist, their ids get reused:

:::BlockQuote
// value is an array of strings for text list, and numbers for numeric list
this.updateRecordValue('field-key', \['First item', 'Third item']);
:::

For multi-select field types (selects, radio buttons, checkboxes), emit an array of new values. Every element in the value must exist in the contextData:

:::BlockQuote
// value is an array of strings
this.updateRecordValue('field-key', \['First item', 'Third item']);// All values must be present in contextData.
// For example: this.updateRecordValue('field-key', \["Fourth item"]) // ❌ ERROR
:::

To add a comment, emit the new comment as a string:

:::BlockQuote
this.addComment('comments-key', 'Hello World!');
:::
