Create a simple textfield plugin

In this example, we will create a material textfield plugin that has a configurable property and stores a value as a form variable. We will:

  1. Create the web component first using Lit and TypeScript.
  2. Add the Form plugin contract to convert the web component to a plugin.
  3. Build the plugin JavaScript file using an npm command.

This tutorial uses the @material/mwctextfield npm package.

Jump to:

You can register this plugin in your tenant:

  • Element name: form-plugin-textfield.
  • Source URL: https://nintexplatform.github.io/form-plugin-examples/examples/build-output/material-textfield.js.

See Add a plugin.

Install the packages

The plugin examples repository provides a simple npm package to install the required packages and build the plugins.

  1. Download or clone the example repository.
  2. Use the command npm install to install the packages.

For more information on using npm, see the npm documentation.

Import the libraries

Create a TypeScript file and import the following:

  • html and LitElement from lit
  • customElement and property from lit/decorators
  • Material text field, along with its styles and the TextField element
  • NintexPlugin from the local /lib folder.

Note: This tutorial builds the final plugin JavaScript using npm. The import modules are npm packages and local libraries provided in the Form plugins repository.


import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import '@material/mwc-textfield/mwc-textfield.js';
import { NintexPlugin } from '../../lib/nintex-plugin';
import { TextField } from '@material/mwc-textfield/mwc-textfield.js';
import { styles } from './material-textfield.styles';

Define the web component

  1. Using the customElement Lit decorator you imported, create a class that extends LitElement.
  2. Note:  Your plugin element name must contain a hyphen - and must not start with ntx-, nwc-, nac-, or nintex-. These prefixes are reserved to prevent conflicts with Nintex elements. For best practice, use your organization's name as a prefix. For example, acme-custom-textfield.

  3. Assign the material textfield styles you imported to a styles variable.
  4. Using the property decorator you imported, create four properties:
    • label (non-null string), using the default property options
    • description (non-null string), using the default property options
    • outlined, with a property options type of Boolean, initialized to false
    • readOnly, with a property options type of Boolean, initialized to false.

Note:  Most examples in this documentation use the reactive properties feature of the Lit framework. When a property is reactive, as denoted by @property() , Lit creates a getter and setter pair for the property and schedules a DOM render whenever the property is changed. If you are not using Lit or a similar framework that offers this functionality and you want the plugin to update when properties are changed, you will need to implement this yourself. For more information on using Lit, see Get started with web components and Lit.


@customElement('form-plugin-textfield')
export class NintexSampleTextfield extends LitElement {
  static styles = styles;

  @property()
  label!: string;
  @property()
  description!: string;
  @property({ type: Boolean })
  outlined: boolean = false;
  @property({ type: Boolean })
  readOnly: boolean = false;
  
}

Add the event to store the value

Plugins use events to pass data to the form. For example, when the user changes the value in a text field, you send an onChange event with the field's new value. The form captures the data in the event to store the new field value.

To add an event to your plugin:

  1. Outside the textfield class you created, declare a typed function that creates and dispatches a custom event called ntx-value-change.
  2. Note: The name of the custom event must be ntx-value-change. For more information on supported event names, see Events.

  3. Inside the textfield class, create a private onChange() function that calls the typed function on the textfield.

//...
const fire = <T>(
  element: HTMLElement,
  data: {
    bubbles?: boolean;
    cancelable?: boolean;
    composed?: boolean;
    detail?: T;
  }
) => {
  const args = {
    bubbles: true,
    cancelable: false,
    composed: true,
    ...data,
  };

  const event = new CustomEvent('ntx-value-change', args);
  element.dispatchEvent(event);
  return event;
};

//...

export class NintexSampleTextfield extends LitElement {

  //...

  private onChange() {
    const el = this.shadowRoot?.getElementById('textfield') as TextField;
    if (el) {
      fire<any>(this, { detail: el.value });
    }
  }
}

Add the render function

Add a render function to the textfield class that returns the mwc-textfield element you imported, and includes the properties and onChange() event you created in the previous steps.

Note: The mwc-textfield element uses a property called helper for its description text and a property called disabled to flag whether the element is read-only or not. In our render function, we map the plugin's properties to the mwc-textfield properties.


export class NintexSampleTextfield extends LitElement {
  
  //...
  
  render() {
    return html` <mwc-textfield
      id="textfield"
      .label="${this.label}"
      .helper="${this.description}"
      ?outlined="${this.outlined}"
      ?disabled="${this.readOnly}"
      @change="${() => this.onChange()}"
    ></mwc-textfield>`;
  }
  
}

Add the Form plugin contract

The web component is now complete. To add the form plugin contract, create a static getMetaConfig() function to return a promise of the contract properties.

Add the properties for the plugin's behavior and appearance:

  1. Add a controlName property with a value of Material Textfield.
  2. This value will appear in the Form designer control toolbox, and at the top of the configuration pane when the control is configured.

  3. Add fallbackDisableSubmit property with a value of false.
  4. Setting this field to false means the user can still submit the form even if this plugin fails to load properly.

  5. Add an iconUrl property with the value of one-line-text.
  6. The plugin will use the same icon as a single-line textfield in the Form designer control toolbox.

  7. Add a version property with the value of 1 (as a string).
  8. This value identifies the form plugin contract version being used.

For more information, see Form designer appearance in the contract reference.

Define custom fields

The plugin has two custom fields:

  • A boolean field, outlined, that controls whether the text field shows an outline.
  • A string field, value, that will hold the value input by the user when submitting the form.

Each of these fields have properties that define how they appear and behave in the Form designer configuration pane.

Create a properties object.

  1. Add an object called outlined with two properties:
    • A type property with a value of boolean.
    • A title property with a value of Show outline.

    Note: The outlined object must be named identically to its counterpart in the web component property we created earlier.

  2. Add an object called value with four properties:
    • A type property with a value of string.
    • A title property with a value of Value.
    • An isValueField property with a value of true.
    • This marks this custom field as containing the value the plugin should return to the form. Only one custom field in your plugin can use this property.

    • A defaultValue property with a value of This is a text field default value.
    • This sets the default value of the custom field.

For more information, see Custom fields in the contract reference.

Define standard fields

Define which standard fields should be available in the control configuration panel. When a field is available, the form designer can configure the field either by form rules, or using the configuration pane.

Create a standardProperties object and add the following properties with a value of true:

  • fieldLabel
  • description
  • defaultValue
  • readOnly.

Note:  There is no default behavior provided for any standard fields. When a plugin's standard field is configured, the value of the field is passed to the plugin. Plugins are responsible for implementing any behavior they need for standard fields. In our example, we provide the implementation by mapping the plugin's properties to the mwc-textfield properties in the render() function. See Add the render function.

For more information, see Standard fields in the contract reference.


export class NintexSampleTextfield extends LitElement {

  //...

  static getMetaConfig(): Promise<NintexPlugin> | NintexPlugin {

    return {
      controlName: 'Material Text field',
      fallbackDisableSubmit: false,
      iconUrl: 'one-line-text',
      version: '1',
      properties: {
        outlined: {
          type: 'boolean',
          title: 'Show Outline',
        },
        value: {
          type: 'string',
          title: 'Value',
          isValueField: true,
          defaultValue: 'This is a text field default value',
        },
      },
      standardProperties: {
        fieldLabel: true,
        description: true,
        defaultValue: true,
        readOnly: true,
      },
    };
  }

Completed plugin


import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import '@material/mwc-textfield/mwc-textfield.js';
import { NintexPlugin } from '../../lib/nintex-plugin';
import { TextField } from '@material/mwc-textfield/mwc-textfield.js';
import { styles } from './material-textfield.styles';

const fire = <T>(
  element: HTMLElement,
  data: {
    bubbles?: boolean;
    cancelable?: boolean;
    composed?: boolean;
    detail?: T;
  }
) => {
  const args = {
    bubbles: true,
    cancelable: false,
    composed: true,
    ...data,
  };

  const event = new CustomEvent('ntx-value-change', args);
  element.dispatchEvent(event);
  return event;
};

@customElement('form-plugin-textfield')
export class NintexSampleTextfield extends LitElement {
  static styles = styles;

  @property()
  label!: string;
  @property()
  description!: string;
  @property({ type: Boolean })
  outlined: boolean = false;
  @property({ type: Boolean })
  readOnly: boolean = false;

  static getMetaConfig(): Promise<NintexPlugin> | NintexPlugin {
    // plugin contract information
    return {
      controlName: 'Material Text field',
      fallbackDisableSubmit: false,
      iconUrl: 'one-line-text',
      version: '1',
      properties: {
        outlined: {
          type: 'boolean',
          title: 'Show Outline',
        },
        value: {
          type: 'string',
          title: 'Value',
          // this is to mark the field as value field. it should only be defined once in the list of properties
          isValueField: true,
          defaultValue: 'This is a text field default value',
        },
      },
      standardProperties: {
        fieldLabel: true,
        description: true,
        defaultValue: true,
        readOnly: true,
      },
    };
  }

  // Render the UI as a function of component state
  render() {
    return html` <mwc-textfield
      id="textfield"
      .label="${this.label}"
      .helper="${this.description}"
      ?outlined="${this.outlined}"
      ?disabled="${this.readOnly}"
      @change="${() => this.onChange()}"
    ></mwc-textfield>`;
  }

  private onChange() {
    const el = this.shadowRoot?.getElementById('textfield') as TextField;
    if (el) {
      fire<any>(this, { detail: el.value });
    }
  }
}

Build the plugin JavaScript

In your development environment console:

  1. If you have not already installed the required packages, type the following command: npm install.
  2. To build the plugin, type the following command: npm run build.

The plugin will be built to the /dist directory.

Upload this plugin to your hosting service and register it in your tenant. See: