Web Component Development Guidelines

The ThingWorx Visual SDK is a collection of web component widgets based on Google Polymer. The components are packaged as npm modules for developing UI and communicating with ThingWorx Composer back-end. You can use the ThingWorx Web Component SDK Utility mub to create widget extensions that you can import into the platform, then use in Mashup Builder. The components are created in the PTCS namespace, using the ptcs- prefix as part the component name, such as ptcs-button.

Overview

This document is organized into sections as follows:

Web Component Development Guidelines

Getting Started

Development

Prerequisites

The ThingWorx Visual SDK is based on Polymer version 3. For development work, you should be familiar with Web Components and Polymer development (https://polymer-library.polymer-project.org/3.0/docs/devguide/feature-overview). You should have a working knowledge of web component concepts such as templates, data binding, Shadow DOM, component life cycle callbacks, and CSS pseudo-classes. This includes using :host, :host(), and pseudo-element ::part to reference elements with matching part attribute in the shadow tree. To learn more about web components, see the following resources:

To migrate a web component that is based on Polymer 2, refer to the Polymer 3 upgrade guide https://polymer-library.polymer-project.org/3.0/docs/upgrade.

Organizing a Web Component Folder

Each web components in the ThingWorx Visual SDK is documented in a Markdown file named README.md under the root of the component folder. As an example, the documentation for button resides in ptcs-button/README.md. The README.md covers the component's visual representation, anatomy, API, and parts that you can style.

The web components follow common organizational guidelines: The main folder of the component has the name of its component with the main implementation of the component in file component-name/component-name.js (e.g. ptcs-button/ptcs-button.js).

As an example, the ptcs-button folder contains:

  • The component's source file: ptcs-button.js
  • The component's README.md file in Markdown format
  • Subfolder test for the component's unit tests
  • Subfolder demo for the component's demo
  • The component's package.json, used for instance to declare dependencies

Other subfolders may exist, like img for images or doc for additional documentation; complex components may have additional files and folders, including subcomponents.

Normally, you only need to import the main file component-name.js in order to use it in your component.

Implementation Considerations

Model vs View

The state (model) of the component should be separated from the view. This cannot be stressed enough.

In practice this means that the full state of the component should be encoded by the properties returned by static get properties(). It should be possible to copy those properties to a new instance of the component and that instance should look and behave as the original.

There are several reasons for this:

  • The copying of properties that is described above actually happens. The dom-repeat "instance stamper" sometimes reuses deleted components by moving properties between components. This can lead to very difficult bugs if state is encoded in the DOM structure or as "invisible" properties.
  • The separation of model and view results in less error prone code
  • The code becomes easier to read if the full state of the component can be understood by only inspecting the registered properties
  • The code becomes easier to read if all operations only affects the properties, and the DOM simply follows along
  • The code becomes easier to update if you can focus on either the state changes or on how to display the changes

The component implementation should therefore consist of two layers:

  1. Manipulation of the state properties
  2. Observers of the state properties that reflects the state into the (shadow) DOM

Observers do of course also often manipulate state properties; the point is that no code should bypass the state properties and write state information directly into the DOM. The DOM should be updated indirectly, in separate code.

Prefer Polymer Data Binding Annotations for Observing Data

You should always try to use Polymer data binding annotations instead of JavaScript observers. Data binding annotations are easier to read and result in fewer bugs.

ARIA

WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) is a technical specification published by W3C (World Wide Web Consortium) that specifies how to increase the accessibility of web pages.

For the Visual SDK, Aria support means that a component should implement keyboard navigation and communicate its state using Aria attributes. The Visual SDK provides focus functionality. You can use it to assign a focused state to subcomponents within a component. You can also use TAB and SHIFT+TAB keyboard shortcuts to navigate between elements that you can focus. Specific components may have additional navigation support, such as:

  • Using the SPACE key to click a focused element.
  • Using arrow keys to move a focused element such as a slider control, or to navigate between elements such as charts and list items.

PTC web components should support this specification. This is a fairly recent requirement, so most of the existing components are still not fully Aria enabled. All new components should however conform to this specification, if the component has any user interaction.

See also https://www.w3.org/WAI/standards-guidelines.

Getting Started

Development Tools and Versions

The ThingWorx Visual SDK development is done in an environment based on NodeJS (http://nodejs.org/) as well as npm, gulp, gulp-cli, and aurelia. The ThingWorx Visual SDK project's version requirements are listed below.

NodeJS

nodejs should be version 8 or later. For ThingWorx 9.0, the NodeJS in use is version 10.15.3. You can verify your installed version by running node -v.

NPM

npm is included with the NodeJS installation. You should use version 5 or later. The current version used for the SDK is 6.12. You can verify your npm version by running: npm -v. To update your npm version, run the following command:

npm install -g npm

Gulp and gulp-cli

To install gulp (http://gulpjs.com/) run the following command:

npm install -g gulp gulp-cli

Aurelia

To install the aurelia (https://aurelia.io/) framework, run the following command:

npm install aurelia-cli -g

The current aurelia-cli version used for the SDK is v.1.2.2.

Download and Installation

  • Download the ThingWorx Visual SDK from the PTC Software Downloads page. The SDK is available under ThingWorx Foundation 9.0 > ThingWorx Visual SDK. The ZIP file is named twx-wc-sdk-[VERSION].zip.
  • Extract the zipped contents to twx-wc-sdk folder inside your project.
  • Install the ThingWorx Visual SDK components and their dependencies by running the following command:
  npm install twx-wc-sdk/ptcs-library

You can add your own dependencies to your project such as @polymer/paper-button. However, adding dependencies for @polymer/polymer and @webcomponents to your package.json file will cause conflicts with the dependencies of the ptcs-library.

The Visual SDK is installed and symbolic links for ptcs modules appear inside your node_modules folder.

Development

After you complete the installation, you can use ptcs modules to create your own custom web components.

In order to have a fully functional Web Component which is a themed widget in the mashup builder, we recommend that you follow these steps:

  1. Build a prototype/beta (demo component): Rapid prototyping helps you identify gaps in the component specification and to align the design with UX intentions.
  2. Create a demo page that shows a working version of the component with the specifics of the component functionality. Creating a working demo helps you test and resolve issues at the component level instead of doing the same after you use the component as a widget in Mashup Builder.
  3. Style the component.
  4. Document the Web Component API and the part attributes are declared for styling.
  5. Write tests for the component.
  6. Publish your component to an npm registry, then use the Visual SDK utility to create a ThingWorx extension from the web component.

Building a Web Component: Declaring Dependencies

Complex components are created using subcomponents. Because there is an existing library of small components, it is easier to build complex components that have consistent behavior and styling. When designing a new complex component, you select subcomponents that meet your user experience requirements. Then, new and more complex functionality is added to create the parent component structure. For example, you can use a primary ptcs-button as part of a submission form component, and would import it as follows:

  import 'ptcs-button/ptcs-button.js';

Because component reuse is a common development methodology, most of the ThingWorx Visual SDK web components include other components within the SDK, in addition to external packages.

Common Imports

You can declare dependencies on other components as import statements at the top of the component file. The dependencies listed below are nearly a bare minimum: A component can also include additional import statements for behaviors, unless the component is invisible or is used only for layout. In those cases, the components can inherit directly from the PolymerElement class.

Polymer

  • @polymer/polymer/polymer-element.js – for Polymer

Styling

To enable styling for your component, include the following files:

Tooltip and Focus Behavior

To enable tooltip and focus functionality, include the following files:

  • ptcs-behavior-focus/ptcs-behavior-focus.js - Allows the component to highlight focused elements consistently and follow keyboard navigation conventions used in ThingWorx Visual SDK components to support accessibility requirements (such as using the SPACE key instead of a mouse click).

List Item in Focus

The focused List item has a blue border that is applied from the style theme. When the text of the list item is truncated, the full text is displayed in the tooltip when you place the pointer on it, or when it is focused.

  • ptcs-behavior-tooltip/ptcs-behavior-tooltip.js - Provides the functionality required to display tooltips in conjunction with the focus behavior. Tooltips in the ThingWorx Visual SDK are also used to display dynamic contents such as truncated text when it overflows its container that has a limited size, and data markers on charts.

Dynamic Tooltip in Chart Data

The image shows a tooltip that displays data values on a crosshair pointer for a chart. Values are displayed for data series on the vertical axis of the crosshair.

Example

For example, the ptcs-button web component of the Visual SDK contains the following import statements:

import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';
import {PTCS} from 'ptcs-library/library.js';
import 'ptcs-icon/ptcs-icon.js';
import 'ptcs-icons/page-icons.js';
import 'ptcs-shadow-style/shadow-part.js';
import 'ptcs-behavior-styleable/ptcs-behavior-styleable.js';
import 'ptcs-behavior-focus/ptcs-behavior-focus.js';
import 'ptcs-behavior-tooltip/ptcs-behavior-tooltip.js';

In addition to dependencies that are mentioned in previous sections, the component uses additional subcomponents that are used to display icons within a button.

Declaring a Component Base Class

To create a component that supports styling and theming, in addition to focus and tooltip behavior, declare the base class as follows:

ACME.Component = class extends PTCS.BehaviorTooltip(PTCS.BehaviorFocus(PTCS.BehaviorStyleable(PTCS.ShadowPart.ShadowPartMixin(PTCS.ThemableMixin(PolymerElement), [])))) {

Note:

  • The component generally uses the two styling behaviors described above, plus PTCS.ThemableMixin. The latter allows the component to be styled using style modules, which is a more efficient, but less flexible way to style components.

If the component extends an existing component that already has these behaviors, then they should not be specified again. For example:

ACME.SpecialButton = class extends PTCS.Button {

To avoid conflict with other namespaces such as Polymer and PTCS when declaring custom web components, declare them in a custom namespace.

When adding new components, consider how they affect the size of the component files. Components should be as light-weight as possible.

Styling Demos

The ptcs-base-theme is an npm module used to apply basic styling to web component. You should only install it to view the demo pages of web components that are served by Polymer. When the component is used as widget in ThingWorx, this component is not used.

The web component demo pages use the following scripts to load styling:

  <script type="module" src="../../ptcs-style-unit/ptcs-style-unit.js"></script>
  <script type="module" src="../../ptcs-base-theme/ptcs-base-theme.js"></script>

or alternatively, using ptcs-multi-theme.js:

  <script type="module" src="../../ptcs-style-unit/ptcs-style-unit.js"></script>
  <script type="module" src="../../ptcs-base-theme/ptcs-multi-theme.js"></script>

The last script creates the drop-down in upper right corner of the web component demo page, that displays available themes in a drop-down, such as the PTCS Base Theme and PTCS Convergence Theme.

Styling a Web Component

The ThingWorx Visual SDK components are designed to have their styling defined externally, with the specific design intent to only include functional CSS styling in the component itself. Following such best practices, the components declare part attributes on subelements in order to expose them for styling. The part attributes are documented in a section of the component's README.md. For example, the ptcs-button web component has following public parts:

Part Attributes Example

The ThingWorx Visual SDK web components are styled using theming to provide a consistent and unified look across widgets. This styling method enables you to easily map and customize theme values to create multiple alternative themes.

The styling is defined for each web component in a separate JSON file, with the theme for the web components as a whole delivered in the mb-theme-engine.js file.

A theme consists of:

  • Theme properties
  • Styles that bind theme properties to web components

For more information about styling and theming web components, see:

Browser Support

The Shadow DOM is supported in Chrome, Firefox (version 63 and later), Opera, and Safari. Microsoft Edge versions that are based on the Chromium browser engine are also supported.

To add support for Microsoft Edge Legacy browser, import a polyfill that enables you to embed web components. However, Edge Legacy still has limitations that make web component development and debugging work more difficult compared to modern browsers with native support.

  • To load the Microsoft Edge Legacy polyfill for your web component demo page, add the following script:
  <script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>

Adding a Web Component to ThingWorx Mashup Builder

After you finish developing and testing your custom web component, we recommend that you publish your widget to an npm registry. Then, you can use the SDK utility (mub) to create widget extensions that you can import and use in Mashup Builder. The utility uses a JSON configuration file for each web component. You can create an extension that includes multiple web components by adding them to the mub/input/widgets.json file.

In addition to the JSON configuration file, you must create following files under your web component folder mub/input/ui/web-component:

  • IDE and runtime custom CSS files.
  • IDE and runtime custom JS code files.

For more information, see Creating Widget Extensions.