Reading Time: 5 minutes

The SharePoint Framework contains a set of standard controls for the property pane. But sometimes you need additional functionality beyond the basic controls. You might need asynchronous updates to the data on a control or a specific user interface. Build a custom control for the property pane to get the functionality you need.

In this post I show how to build a text box property pane using Typescript, i.e easy way to create simple custom Property Pane without react.

Note : Next post I will show you how to build a custom property pane using React.js

Steps

Step 1:

Open command Prompt and create a folder “spfxCustomPropertyPane” under your favourite SPFx project

Step 2:

Create a new ” PropertyPaneCustomTextField ” web part by running the Yeoman SharePoint Generator.

When prompted fill all solution and web part information, refer below

At this point, Yeoman creates the project scaffolding (folders & files) and installs the required dependencies by running npm install

Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your web part. Here I am using Visual Studio Code

Step 3

Open the code in Visual Studio Code – for that type code . in the command Prompt

Create a folder “Modules” under web part folder, refer below

Create a file ” PropertyPaneCustomTextField.ts” under Modules folder, manage the control functionality.

Open the PropertyPaneCustomTextField.ts file

Import the Custom Property Pane Class and Interfaces

IPropertyPaneCustomFieldProps – This interface provides key properties and methods that help in developing the pane property. Properties and methods available are the following.

IPropertyPaneField – This interface provides a few properties that can be inherited for defining the custom pane property

import { IPropertyPaneField, IPropertyPaneCustomFieldProps, PropertyPaneFieldType } from '@microsoft/sp-property-pane';

Create interface “PropertyPaneCustomTextFieldProps” to structure your Property Pane parameters. The property definition is written as a function which inherits data from class and interface components. Here, a custom interface is introduced to input the user defined custom properties.

export interface IPropertyPaneCustomTextFieldProps{
  properties:any;
  label:string;
  description?:string;
  color?:string;
  backgroundcolor?:string;
  defaultvalue?:string;
}

In this above interface i have added properties to get all control properties

  1. label to give a header to the control
  2. ? means optional property
  3. description to give control details below the control
  4. color to give label font color
  5. backgroundcolor to give control background
  6. defaultvalue to give default value to the control

Create a class “PropertyPaneCustomTextField and implements IPropertyPaneField and type IPropertyPaneCustomFieldProps, the class is defined, which contains the variables, constructor, and render method

export class PropertyPaneCustomTextField implements IPropertyPaneField<IPropertyPaneCustomFieldProps>
{
  
}

Declare IPropertyPaneCustomFieldProps mandatory variables

public type: any = PropertyPaneFieldType.Custom;
public targetProperty:string;
public properties: IPropertyPaneCustomFieldProps;

Declare two local variable to get all properties as config and maintain the currentvaue

private config : IPropertyPaneCustomTextFieldProps;
private currentValue:string = "";

Then create a constructor to get all property inputs from user, In this constructor get all config property parameters, webpart context, and initial render and dispose events. Also create two methods to handle render and dispose events and assign the config parameter to local config variable.

The constructor is used to initialise the variables.

constructor(targetProperty:string,
    config : IPropertyPaneCustomTextFieldProps,
    context?:any)
    {
    this.targetProperty = targetProperty;
    this.properties = {
      key: "MyCustomControl",
      context: context,
      onRender : this.render.bind(this),
      onDispose : this.dispose.bind(this)
    };
    this.config = config;
  }

  private render()
  {

  }
  private dispose()
  {
    
  }

The render method will display the data. The custom function or the components are used for rendering the data.

Inside the render method to build the control and add events, here I have added HeaderLabel, Textbox and description label with configure default textbox value, description, background color and label header font color

${this.config.backgroundcolor}

${this.config.color}

${this.config.defaultvalue}

${this.config.description

private render(element:HTMLElement, context:any,changeCallback:(targetProperty:string, newValue:any)=>void)
    {
      this.currentValue = this.config.properties[this.targetProperty];
        let html =
        `<div style="border: 1px solid #ccc!important;border-radius: 5px;padding-left: 5px;padding-right: 3px;background-color:${this.config.backgroundcolor || "red"}">
          <div class="ms-TexField">
          <div class="ms-TextFied-wrapper">
           <label style="display: block;width: 100%;color:${this.config.color || "yellow"};">${this.config.label}</label>
           <input style="padding: 8px;display: block;width: 93%;border: 1px solid #ccc!important;border-radius: 5px" type="text" value="${this.currentValue || this.config.defaultvalue || ""}">
          </div>
        </div>
        <span class="description">${this.config.description || ""}</span>
        </div>
      </div>
        `;
        element.innerHTML = html;

        this.addEvents(element,changeCallback);
    }

Add two local method to manage events, add the events to your control, then add the functionality for the events. Here I am get the value from textbox using on change and assign to current value i,e newValue.

private addEvents(element:HTMLElement, callback:(targetProperty:string, newValue:any)=>void ){
    let inputTextElement : HTMLInputElement = element.getElementsByTagName('input')[0];

    inputTextElement.onchange=()=>{
      this.applyChanges(element, inputTextElement, callback);
    };
}

private applyChanges(element: HTMLElement, inputTextElement : HTMLInputElement, callback:(targetProperty:string, newValue:any)=>void ){
  let newValue = inputTextElement.value;
  callback(this.targetProperty, newValue);
}

Finally add dispose method to clear the htmlelement

private dispose(element:HTMLElement)
{
  element.innerHTML = "";
}

Now our Property control is ready, need to use the custom property pane module in our webpart. for that Import the module in webpart

import { PropertyPaneCustomTextField } from "./../Modules/PropertyPaneCustomTextField";

The goto getPropertyPaneConfiguration() method and add new custom propertypane

new PropertyPaneCustomTextField('mytextbox',{
                properties: this.properties,
                label:"Full Name",
                description:"Please enter full name",
                color:"green",
                backgroundcolor:"yellow",
                defaultvalue: "default value"
              })

To bring the return value to webpart

Add the propertypane control name in props, then get the propoerties value from renderwebpart method

export interface IPropertyPaneCustomTextFieldWebPartProps {
  description: string;
  mytextbox:string;
}
<p class="${ styles.description }">${escape(this.properties.mytextbox)}</p>

gulp serve and execute the webpart

After adding the web part to the page for the first time and opening its property pane and see the custom propertypane

Conclusion

SharePoint Framework contains a set of standard controls for the property pane. But sometimes you need additional functionality beyond the basic controls. SharePoint Framework allows you to build custom controls to deliver the required functionality. In this post you learned how to create a simple custom property pane using Typescript.

Here you have learned how to build simple custom pane property which can be added to property panes. The interfaces, class, and functions are used for defining the data. The rendering can be done on the same file or using components.

In the next article, how to build the custom pane property pane using react components.