Create your first component
In this tutorial, we demonstrate how to build a linear slider code component that enables users to change the numeric values using a visual slider instead of typing the values in the column.
Note
Unsure about entity vs. table? See Developers: Understand terminology in Microsoft Dataverse.
The following steps are required to build a linear slider code component:
- Create a new component project
- Implementing manifest
- Implement component logic using TypeScript
- Add style to the code components
- Build your code components
- Packaging code components
- Adding component to a model-driven app
- Adding component to a canvas app
Prerequisites
For this tutorial you need install the following components:
- Visual Studio Code (VSCode) (Ensure the Add to PATH option is select)
- node.js (LTS version is recommended)
- Microsoft Power Platform CLI (Use either the Visual Studio Code extension or the MSI installer)
- .NET Build tools by installing one of the following: (At minimum select the workload
.NET build tools.)- Visual Studio 2022
- Visual Studio 2019
Note
You may prefer to use the .NET 5.x SDK instead of the Build Tools for Visual Studio. In this case, instead of using msbuild you would use dotnet build.
Tip
It is also recommended to install git for source control.
Creating a new component project
To create a new project:
Open a command prompt window. Create a new folder for the project using the following command:
mkdir LinearInputOpen your
LinearInputfolder inside Visual Studio Code. The quickest way to start is by usingcd LinearInputand then runningcode .from the command prompt once you are in the project directory. This command opens your component project in Visual Studio Code.Open a new terminal inside Visual Studio Code using Terminal -> New Terminal.
At the terminal prompt, create a new component project by passing basic parameters using the pac pcf init command.
pac pcf init --namespace SampleNamespace --name LinearInputControl --template fieldThe above command also runs the
npm installcommand for you to setup the project build tools.Running 'npm install' for you...Note
If you receive the error
The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program., make sure you have installed node.js (LTS version is recommended) and all other prerequisites.After npm install, you will need to generate ManifestDesignTypes.d.ts file in this directory using the below command."
npm run refreshTypes
Implementing manifest
The control manifest is an XML file that contains the metadata of the code component. It also defines the behavior of the code component. In this tutorial, this manifest file is created under the LinearInputControl subfolder. When you open the ControlManifest.Input.xml file in Visual Studio Code, you'll notice that the manifest file is predefined with some properties. More information: Manifest.
Make changes to the predefined manifest file, as shown here:
The control node defines the namespace, version, and display name of the code component. Now, define each property of the control node as shown here:
namespace: Namespace of the code component.
Constructor: Constructor of the code component.
Version: Version of the component. Whenever you update the component, you need to update the version to see the latest changes in the runtime.
display-name-key: Name of the code component that is displayed on the UI.
description-name-key: Description of the code component that is displayed on the UI.
control-type: The code component type. Only standard types of code components are supported.
<?xml version="1.0" encoding="utf-8" ?> <manifest> <control namespace="SampleNamespace" constructor="LinearInputControl" version="1.1.0" display-name-key="LinearInputControl_Display_Key" description-key="LinearInputControl_Desc_Key" control-type="standard">
The property node defines the properties of the code component like defining the data type of the column. The property node is specified as the child element under the
controlelement. Define the property node as shown here:name: Name of the property.
display-name-key: Display name of the property that is displayed on the UI.
description-name-key: Description of the property that is displayed on the UI.
of-type-group: The of-type-group is used when you want to have more than two data type columns. Add the of-type-group element as a sibling to the
propertyelement in the manifest. Theof-type-groupspecifies the component value and can contain whole, currency, floating point, or decimal values.usage: Has two properties, bound and input. Bound properties are bound only to the value of the column. Input properties are either bound to a column or allow a static value.
required: Defines whether the property is required.
<property name="controlValue" display-name-key="controlValue_Display_Key" description-key="controlValue_Desc_Key" of-type-group="numbers" usage="bound" required="true" />
The resources node defines the visualization of the code component. It contains all the resources that build the visualization and styling of the code component. The code is specified as a child element under the resources element. Define the resources as shown here:
code: Refers to the path where all the resource files are located.
<resources> <code path="index.ts" order="1" /> <css path="css/LinearInputControl.css" order="1" /> </resources>The overall manifest file should look something like this:
<?xml version="1.0" encoding="utf-8" ?> <manifest> <control namespace="SampleNamespace" constructor="LinearInputControl" version="1.1.0" display-name-key="LinearInputControl_Display_Key" description-key="LinearInputControl_Desc_Key" control-type="standard"> <type-group name="numbers"> <type>Whole.None</type> <type>Currency</type> <type>FP</type> <type>Decimal</type> </type-group> <property name="controlValue" display-name-key="controlValue_Display_Key" description-key="controlValue_Desc_Key" of-type-group="numbers" usage="bound" required="true" /> <resources> <code path="index.ts" order="1" /> <css path="css/LinearInputControl.css" order="1" /> </resources> </control> </manifest>
Save the changes to the
ControlManifest.Input.xmlfile.
Implementing component logic
The next step after implementing the manifest file is to implement the component logic using TypeScript. The component logic should be implemented inside the index.ts file. When you open the index.ts file in the Visual Studio Code, you'll notice that the four essential functions are predefined. Now, let's implement the logic for the code component.
- Open the
index.tsfile in the code editor of your choice. - Update the
LinearInputControlclass with the following code:
import { IInputs, IOutputs } from "./generated/ManifestTypes";
export class LinearInputControl implements ComponentFramework.StandardControl<IInputs, IOutputs> {
private _value: number;
private _notifyOutputChanged: () => void;
private labelElement: HTMLLabelElement;
private inputElement: HTMLInputElement;
private _container: HTMLDivElement;
private _context: ComponentFramework.Context<IInputs>;
private _refreshData: EventListenerOrEventListenerObject;
public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement): void {
this._context = context;
this._container = document.createElement("div");
this._notifyOutputChanged = notifyOutputChanged;
this._refreshData = this.refreshData.bind(this);
// creating HTML elements for the input type range and binding it to the function which refreshes the control data
this.inputElement = document.createElement("input");
this.inputElement.setAttribute("type", "range");
this.inputElement.addEventListener("input", this._refreshData);
//setting the max and min values for the control.
this.inputElement.setAttribute("min", "1");
this.inputElement.setAttribute("max", "1000");
this.inputElement.setAttribute("class", "linearslider");
this.inputElement.setAttribute("id", "linearrangeinput");
// creating a HTML label element that shows the value that is set on the linear range control
this.labelElement = document.createElement("label");
this.labelElement.setAttribute("class", "LinearRangeLabel");
this.labelElement.setAttribute("id", "lrclabel");
// retrieving the latest value from the control and setting it to the HTMl elements.
this._value = context.parameters.controlValue.raw!;
this.inputElement.setAttribute("value", context.parameters.controlValue.formatted ? context.parameters.controlValue.formatted : "0");
this.labelElement.innerHTML = context.parameters.controlValue.formatted ? context.parameters.controlValue.formatted : "0";
// appending the HTML elements to the control's HTML container element.
this._container.appendChild(this.inputElement);
this._container.appendChild(this.labelElement);
container.appendChild(this._container);
}
public refreshData(evt: Event): void {
this._value = (this.inputElement.value as any) as number;
this.labelElement.innerHTML = this.inputElement.value;
this._notifyOutputChanged();
}
public updateView(context: ComponentFramework.Context<IInputs>): void {
// storing the latest context from the control.
this._value = context.parameters.controlValue.raw!;
this._context = context;
this.inputElement.setAttribute("value", context.parameters.controlValue.formatted ? context.parameters.controlValue.formatted : "");
this.labelElement.innerHTML = context.parameters.controlValue.formatted ? context.parameters.controlValue.formatted : "";
}
public getOutputs(): IOutputs {
return {
controlValue: this._value
};
}
public destroy(): void {
this.inputElement.removeEventListener("input", this._refreshData);
}
}
- Save the change to the
index.tsfile.
Adding style to the code component
Developers and app makers can define their styling to represent their code components visually using CSS. CSS allows the developers to describe the presentation of code components, including style, colors, layouts, and fonts. The linear input component's init method creates an input element and sets the class attribute to linearslider. The style for the linearslider class is defined in a separate CSS file. Additional component resources like CSS files can be included with the code component to support further customizations.
Important
When you implement styling to your code components using CSS, ensure that the CSS is scoped to your control using the automatically generated CSS classes applied to the container DIV element for your component. If your CSS is scoped globally, it will likely break the existing styling of the form or screen where the code component is rendered. If using a third-party CSS framework, use a version of that framework that is already namespaced or otherwise wrap that framework in a namespace manually either by hand or using a CSS preprocessor.
Create a new
csssubfolder under theLinearInputControlfolder.Create a new
LinearInputControl.cssfile inside thecsssubfolder.Add the following style content to the
LinearInputControl.cssfile:.SampleNamespace\.LinearInputControl input[type=range].linearslider { margin: 1px 0; background:transparent; -webkit-appearance:none; width:100%;padding:0; height:24px; -webkit-tap-highlight-color:transparent } .SampleNamespace\.LinearInputControl input[type=range].linearslider:focus { outline: none; } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-webkit-slider-runnable-track { background: #666; height:2px; cursor:pointer } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-webkit-slider-thumb { background: #666; border:0 solid #f00; height:24px; width:10px; border-radius:48px; cursor:pointer; opacity:1; -webkit-appearance:none; margin-top:-12px } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-moz-range-track { background: #666; height:2px; cursor:pointer } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-moz-range-thumb { background: #666; border:0 solid #f00; height:24px; width:10px; border-radius:48px; cursor:pointer; opacity:1; -webkit-appearance:none; margin-top:-12px } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-ms-track { background: #666; height:2px; cursor:pointer } .SampleNamespace\.LinearInputControl input[type=range].linearslider::-ms-thumb { background: #666; border:0 solid #f00; height:24px; width:10px; border-radius:48px; cursor:pointer; opacity:1; -webkit-appearance:none; }Save the
LinearInputControl.cssfile.Note that the
ControlManifest.Input.xmlfile include theCSSresource file inside the resources element.<resources> <code path="index.ts" order="1"/> <css path="css/LinearInputControl.css" order="1"/> </resources>
Note
Power Apps component framework uses the concept of implementing String(resx) web resources that is used to manage the localized strings shown on any user interface. More information: String(Resx) web resources.
See Localization API sample, to learn how to localize code components using resx web resources.
Build your code components
After you finish adding manifest, component logic, and styling, build the code components using the command:
npm run build
The build generates an updated TypeScript type declaration file under the LinearInputControl/generated folder.
The component is compiled into the out/controls/LinearInputControl folder. The build artifacts include:
- bundle.js – Bundled component source code.
- ControlManifest.xml – Actual component manifest file that is uploaded to the Microsoft Dataverse organization.
Debugging your code component
Once you're done implementing the code component logic, run the following command to start the debugging process. More information: Debug code components
npm start watch
Packaging your code components
Follow these steps to create and import a solution file:
Create a new folder Solutions inside the LinearInputControl folder and navigate into the folder.
Create a new solution project in the LinearInputControl folder using the pac solution init command:
pac solution init --publisher-name Samples --publisher-prefix samplesNote
The publisher-name and publisher-prefix values must be the same as either an existing solution publisher, or a new one that you want to create in your target environment.
Once the new solution project is created, you need to refer to the location where the created component is located. You can add the reference by using the following command:
pac solution add-reference --path ..\Note
The path provided here is related to the current Solutions folder that was created underneath the LinearInputControl folder. You can also provide an absolute path.
To generate a zip file from your solution project, when inside the the
cdsprojsolution project directory, using the following command:msbuild /t:restoreOr if you have installed the .NET 5 SDK:
dotnet buildAgain run the following command:
msbuildNote
If you receive the error
Missing required tool: MSBuild.exe/dotnet.exe. AddMSBuild.exe/dotnet.exein Path environment variable or useDeveloper Command Prompt for Visual Studio Code. As mentioned in Prerequisites, you must install .NET build tools.Tip
You will see the message Do not use the
evalfunction or its functional equivalents, when you build the solution file using themsbuildcommand and import it into Dataverse and run the solution checker. Re build the solution file using the commandmsbuild/property:configuration=Releaseand reimport the solution into Dataverse and run the solution checker. More information: Debug code components.The generated solution zip file is located in the
Solution\bin\debugfolder.Manually import the solution into Dataverse using the web portal once the zip file is ready or automatically using the Microsoft Power Platform Build Tools.
Note
Manually publish the customizations if you are importing unmanaged solution.
Adding code components in model-driven apps
To add a code component like a linear input component, follow the steps mentioned in the article Add components to columns and tables.
Adding code components to a canvas app
To add the code components to a canvas app, follow the steps in the article Add code components to a canvas app.
Adding code components to a portal
To add the code component to a portal, follow the steps in the article Use code components in portals.
See also
Download sample components
Learn Power Apps component framework
Update existing Power Apps component framework components
Microsoft Power Platform Build Tools
Power Apps component framework API reference
Power Apps component framework overview
Debug code components
Feedback
Submit and view feedback for