---
title: Example - Developing a custom form component
related:
  - https://docs.kentico.com/13/developing-websites/form-builder-development.md
  - https://docs.kentico.com/13/developing-websites/form-builder-development/developing-form-components.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

This page provides a step-by-step example demonstrating the process of creating, configuring, and registering a form component in the system.

## Developing the RgbInput custom form component

In this example, we implement a form component that enables users to specify a color in the RGB hexadecimal format split into three _input_ elements (representing the red, green, and blue components of the color, respectively) by using the HTML5 color selector. On form submit, the partial color values are concatenated using the component's _GetValue_ method and the resulting string inserted into the database.

You can see an example of the form component rendered as part of a form in the image below. Clicking on the Color selector opens a dialog window that allows users to select a color using a familiar interface. Once a color is selected, the color values are propagated to the three _input_ elements via JavaScript.

![Selecting a color using the color picker of the form component](https://docs.kentico.com/docsassets/13/example-developing-a-custom-form-component/RgbInput_Form_Component.png "Selecting a color using the color picker of the form component")

> **Tip:** **Tip**: To view the full code of the example, you can inspect and download the [LearningKit project](https://github.com/Kentico/LearningKit-Mvc) on GitHub. You can also run the LearningKit website by connecting the project to an Xperience database.

1. Open your live site project in Visual Studio.

2. In a suitable location within your project structure (e.g., in the project's root), create a _\~/Models/FormComponent&#x73;_&#x66;older structure to store all classes holding the component's logic.

3. Create a new **RgbInputComponentProperties** properties class that inherits from **FormComponentProperties**. In the class, implement the following:

   - Call the base class constructor from the derived class and set the data type of the underlying database column to _Text,_ and its maximum length to 7 (the length of the hexadecimal string representing a submitted color, including the _'#'_ symbol).
   - Override the _DefaultValue_ property and specify its [editing component](https://docs.kentico.com/13/developing-websites/form-builder-development/developing-form-components/defining-form-component-properties.md).

   ```csharp

       public class RgbInputComponentProperties : FormComponentProperties<string>
       {
           // Sets the component as the editing component of its DefaultValue property
           // System properties of the specified editing component, such as the Label, Tooltip, and Order, remain set to system defaults unless explicitly set in the constructor
           [DefaultValueEditingComponent("RgbInputComponent", DefaultValue = "#ff0000")]
           public override string DefaultValue
           {
               get;
               set;
           }

           // Initializes a new instance of the RgbInputComponentProperties class and configures the underlying database field
           public RgbInputComponentProperties()
               : base(FieldDataType.Text, 7)
           {
           }
       }


   ```

4. Create a new **RgbInputComponent** form component class that inherits from **FormComponent**. Implement the following members:

   - _RedComponent_,_GreenComponent,_ and _BlueComponent_ properties used to store the partial color intensity values\*.\*
   - Override the _CustomAutopostHandling_ property and set it to _true_, which disables automatic server-side evaluation of the component's values. See [Developing form components](https://docs.kentico.com/13/developing-websites/form-builder-development/developing-form-components.md) for more information.
   - Override the _GetValue_ method. The method concatenates and normalizes the submitted partial color intensities using string interpolation.
   - Override the _SetValue_ method which you can use to specify the initial values for each property.

   ```csharp

       public class RgbInputComponent : FormComponent<RgbInputComponentProperties, string>
       {
           public const string IDENTIFIER = "RgbInputComponent";

           // Specifies that the property carries data for binding by the form builder
           [BindableProperty]
           // Used to store the value of the input field of the component
           public string RedComponent { get; set; } = "ff";

           [BindableProperty]
           public string GreenComponent { get; set; } = "00";

           [BindableProperty]
           public string BlueComponent { get; set; } = "00";

           // Disables automatic server-side evaluation for the component
           public override bool CustomAutopostHandling => true;

           // Gets the submitted values of the three properties and normalizes them to form a hexadecimal string of length 7,
           // e.g., in case a color was submitted in the #363 shorthand (representing #336633)
           // The returned value is subsequently saved to the corresponding column in the form's database table
           public override string GetValue()
           {
               return $"#{NormalizeReceivedValue(RedComponent)}{NormalizeReceivedValue(GreenComponent)}{NormalizeReceivedValue(BlueComponent)}";
           }

           // Normalizes individual submitted color components to 2 characters, e.g., F -> FF, 5 -> 55
           private string NormalizeReceivedValue(string value)
           {
               return value.Length == 1 ? value + value : value;
           }

           // Sets values of the properties (represented by individual 'input' elements)
           public override void SetValue(string value)
           {
               if (!String.IsNullOrEmpty(value))
               {
                   RedComponent = value.Substring(1, 2);
                   GreenComponent = value.Substring(3, 2);
                   BlueComponent = value.Substring(5, 2);
               }
               else
               {
                   SetValue("#ff0000");
               }
           }
       }


   ```

5. Create a partial view in _\~/Views/Shared/FormComponents/._ The view defines the visual element of the component. Note that the name of the view must correspond to the identifier you assign to the form component upon its registration to the system, i.e.,  **_\__&#x52;gbInputComponent.cshtml** for this example. In the view:

   - Retrieve the collection of system attributes via the **ViewData.Kentico().GetEditorHtmlAttributes** method (from the _Kentico.Forms.Web.Mvc_ namespace).
   - Specify input fields for the properties defined in the main component class using the **HtmlHelper.TextBoxFor** extension method. Pass the collection of system attributes together with any attributes you require to the method's _htmlAttributes_ parameter.
   - Add an HTML5 color selector element. We recommend using a custom _HtmlHelper_ extension method together with the [TagBuilder](https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/views/using-the-tagbuilder-class-to-build-html-helpers-cs) to render custom input elements (this example uses the **CustomInput** extension method, the code for which is provided below). The _TagBuilder_ automatically handles the encoding of all HTML attributes and expedites the process of writing custom inputs. The _window.kentico.updatableFormHelper.updateForm(this.form)_ function call in the input's **onchange** event ensures any depending visibility conditions are evaluated only when a new color is chosen using the color selector.

   ```csharp title="_RgbInputComponent.cshtml"

   @using Kentico.Forms.Web.Mvc
   @using LearningKit.FormBuilder

   @model LearningKit.FormBuilder.FormComponents.RgbInputComponent

   @* Gets a collection of system HTML attributes necessary for the correct functionality of the component input fields *@
   @{
       IDictionary<string, object> htmlAttributes = ViewData.Kentico().GetEditorHtmlAttributes();
   }

   @{
       @* Specifies additional HTML attributes for the input fields *@
       if (htmlAttributes.ContainsKey("style"))
       {
           htmlAttributes["style"] += " width:50px;";
       }
       else
       {
           htmlAttributes["style"] = "width:50px;";
       }

       @* Sets the partial color inputs to read-only, ensuring users can only specify the color intensities via the color selector *@
       htmlAttributes["readonly"] = "";
   }

   @* Renders basic text input fields to store the partial color intensity values *@
   @Html.Raw("#")

   @Html.TextBoxFor(m => m.RedComponent, htmlAttributes)

   @Html.TextBoxFor(m => m.GreenComponent, htmlAttributes)

   @Html.TextBoxFor(m => m.BlueComponent, htmlAttributes)

   @* Specifies additional attributes for the color selector *@
   @{
       htmlAttributes.Remove("readonly");

       // The data attributes are used by the accompanying JavaScript logic to assign values to the input fields represented by
       // the corresponding identifiers whenever a different color is selected using the selector
       htmlAttributes["data-red-id"] = Html.IdFor(m => Model.RedComponent);
       htmlAttributes["data-green-id"] = Html.IdFor(m => Model.GreenComponent);
       htmlAttributes["data-blue-id"] = Html.IdFor(m => Model.BlueComponent);

       // The window.kentico.updatableFormHelper.updateForm(this.form) ensures any visibility conditions depending
       // on fields based on this component only evaluate after a color has been selected using the color selector
       htmlAttributes["onchange"] = "parseColorSelector(this); window.kentico.updatableFormHelper.updateForm(this.form)";
   }

   @* Renders the color selector using a custom HtmlHelper extension method *@
   @Html.CustomInput("color", "colorSelector", Model.GetValue(), htmlAttributes)

   <span><em>(Color selector)</em></span>


   ```

The following excerpt contains a possible implementation of the _CustomInput_ extension method for _HtmlHelper_. You can place the method within a class dedicated to _HtmlHelper_ extension methods or, for this example, create a new static **FormBuilderExtensions** class under _\~/FormBuilder/FormBuilderExtensions.cs_.

<!-- dev-model:mvc start -->

**MVC 5 development model.** Applies only when building with ASP.NET MVC 5. If this page also covers ASP.NET Core, that version is in its own block.

```csharp title="CustomInput HtmlHelper extension method"

        // Renders an 'input' element of the specified type and with the collection of provided attributes
        public static MvcHtmlString CustomInput(this HtmlHelper helper, string inputType, string name, object value, IDictionary<string, object> htmlAttributes)
        {
            TagBuilder tagBuilder = new TagBuilder("input");

            // Specifies the input type, name, and value attributes
            tagBuilder.MergeAttribute("type", inputType);
            tagBuilder.MergeAttribute("name", name);
            tagBuilder.MergeAttribute("value", value.ToString());

            // Merges additional attributes into the element
            tagBuilder.MergeAttributes(htmlAttributes);            

            return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.StartTag)); 
        }


```

<!-- dev-model:mvc end -->

<!-- dev-model:core start -->

**ASP.NET Core development model.** Applies only when building with ASP.NET Core. If this page also covers MVC 5, that version is in its own block.

```csharp title="CustomInput HtmlHelper extension method"

public static IHtmlContent CustomInput(this IHtmlHelper helper, string inputType, string name, object value, IDictionary<string, object> htmlAttributes)
{
    TagBuilder tagBuilder = new TagBuilder("input");
    tagBuilder.TagRenderMode = TagRenderMode.StartTag;

    // Specifies the input type, name, and value attributes
    tagBuilder.MergeAttribute("type", inputType);
    tagBuilder.MergeAttribute("name", name);
    tagBuilder.MergeAttribute("value", value.ToString());

    // Merges additional attributes into the element
    tagBuilder.MergeAttributes(htmlAttributes);

    using (var writer = new StringWriter())
    {
        tagBuilder.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
        return new HtmlString(writer.ToString());
    }
}

```

<!-- dev-model:core end -->

6. [Register the form component](https://docs.kentico.com/13/developing-websites/form-builder-development/developing-form-components.md#registering-form-components) in the system. Place the following registration attribute over the _RgbInputComponent_ class definition in **RgbInputComponent.cs**:

   ```csharp

   [assembly: RegisterFormComponent(RgbInputComponent.IDENTIFIER, typeof(RgbInputComponent), "RGB color input", Description = "Allows users to specify a color in the RGB hexadecimal format either manually, or by using a color selector", IconClass = "icon-palette")]


   ```
7. Add a file containing a JavaScript function that watches for _change_ events fired by the color selector element and fills the partial color input fields by parsing the emitted value.
   - Create a **\~/Content/FormComponents/RgbInputComponent** folder in your project and place the script file there. The location ensures that the script is automatically bundled and linked in the form builder interface, and on all pages with [page builder editable areas](https://docs.kentico.com/13/developing-websites/page-builder-development/creating-pages-with-editable-areas.md) (which could contain a _Form_ widget displaying the component).

> **Info:** The code used in this sample function is intentionally written in plain JavaScript. You are free to implement the functionality in a framework of your choice.

```js title="colorInputParser.js"

// Modifies the partial intensity values of the RGB input fields whenever a different color is selected
var parseColorSelector = function (target) {
    document.getElementById(target.getAttribute('data-red-id')).value = target.value.substring(1, 3);
    document.getElementById(target.getAttribute('data-green-id')).value = target.value.substring(3, 5);
    document.getElementById(target.getAttribute('data-blue-id')).value = target.value.substring(5, 7);
};

```

8. (Optional) Define a new validation rule that tests whether the submitted value is in the hexadecimal format. [Apply the rule](https://docs.kentico.com/13/managing-website-content/forms/composing-forms.md) to form fields based on this form component.

   > **Tip:** To learn more about validation rules in the form builder, refer to [Defining field validation rules](https://docs.kentico.com/13/developing-websites/form-builder-development/defining-field-validation-rules.md).

   ```csharp

   using System;

   using Kentico.Forms.Web.Mvc;

   using LearningKit.FormBuilder.CustomValidationRules;

   // Registers the validation rule in the system
   [assembly: RegisterFormValidationRule("IsHexadecimalNumberValidationRule", typeof(IsHexadecimalNumber), "Is hexadecimal number", Description = "Checks whether the submitted input is a hexadecimal string (including the leading # character).")]

   namespace LearningKit.FormBuilder.CustomValidationRules
   {
       [Serializable]
       public class IsHexadecimalNumber : ValidationRule<string>
       {
           // Gets the title of the validation rule as displayed in the list of applied validation rules
           public override string GetTitle()
           {
               return "Input is a hexadecimal number.";
           }

           // Returns true if the field value is in the hexadecimal format
           protected override bool Validate(string value)
           {
               // Fails if the submitted string does not contain a leading '#' character
               if (value[0] != '#')
               {
                   return false;
               }

               // Strips the leading '#' character
               value = value.Substring(1);

               // Tries to convert the submitted value
               bool success = int.TryParse(value, System.Globalization.NumberStyles.AllowHexSpecifier, null, out int variable);

               return success;
           }
       }
   }

   ```

The form component is registered in the system and ready to be used within the form builder framework. Users can insert it into forms on the **Form builder** tab in the **Forms** application.
