Customizing Form Widget Markup With Kentico 12 - Part Two

By Shelby Tieche On January 10, 2020

Customizing Form Widget Markup With Kentico 12 - Part Two

In my last blog post, Customizing Form Widget Markup With Kentico 12, Part 1,  I walked through how to set up a Global rendering config file on a Kentico 12 site to customize your markup for your forms created with Form Builder. We did this by modifying the FormFieldRenderingConfiguration and FormWidgetRenderingConfiguration properties, and we ended up with a form looking like this:

custom markup form created with Form Builder

This blog post will tack on to the previous post and go over the same concept of customizing your forms’ markup. However,  instead of modifying the global rendering configurations, we will be adding contextual styling when your form renders.  This will allow you to do things like add custom classes for certain input types as well as ADA compliance. I will be covering how to customize all select inputs to be cross-browser friendly, visibly add validation to required fields, and add a class when an input has a value on submit of a form. NOTE: hotfix 12.0.14 is required for your Kentico site before applying these customizations to your forms. 

Setting Up Your Project for Custom Contextual Form Markup and Configurations

1. Add a  custom class to your project in your App_Start folder called FormBuilderContextualConfig.cs. This will be similar to the other class created in part one of this blog series. 

using Kentico.Forms.Web.Mvc;
using System;

namespace ProjectCodeName.Web.App_Start
{
    public class FormBuilderContextualConfig
    {
        public static void RegisterCustomEventHandlers()
        {
            FormFieldRenderingConfiguration.GetConfiguration.Execute += InjectMarkupIntoKenticoComponents;
        }

        private static void InjectMarkupIntoKenticoComponents(object sender, GetFormFieldRenderingConfigurationEventArgs e)
        {
            // Checks for default Kentico form components to apply custom markup 
            if (!e.FormComponent.Definition.Identifier.StartsWith("Kentico", StringComparison.InvariantCultureIgnoreCase))
            {
                return;
            }
            // Class specific calls will go here
        }   
    }
}


2. Call the new static method in your Global.asax .cs so it runs during initialization.
FormBuilderContextualConfig.RegisterCustomEventHandlers();
Similar to the custom global rendering configurations, these are the only steps you need to start adding contextual markup to your forms created with Kentico’s form builder. Using the GetFormFieldRenderingConfiguration event arguments gives you access to a few properties that you can reference here

In the following examples, we will be working with both the Configuration and FormComponent properties in three custom methods we will be creating. 

Adding Custom Markup to Specific Input Types

In this example, we will target all dropdown inputs and adding custom HTML and CSS to make the UX for each dropdown look the same on all browsers. This is important for UX because native dropdowns render differently across browsers. This solution will give them a universal look to match any design or style guide given to you.

1. Create a new private method AddDropDownSpecificMarkup, and pass in the GetFormFieldRenderingConfigurationEventArgs event to get access to various properties. In this example, we will use the FormComponent property.  

2. Add check to your method  for targeting if an input is a dropdown and add the following code to your if statement.

private static void AddDropDownSpecificMarkup(GetFormFieldRenderingConfigurationEventArgs e)
{
    // Adds custom CSS class to all DropDown fields
    if (e.FormComponent is DropDownComponent)
    {
        if (e.Configuration.RootConfiguration.HtmlAttributes.ContainsKey("class"))
        {
            e.Configuration.RootConfiguration.HtmlAttributes["class"] += " styled-dropdown";
        }
        else
        {
            e.Configuration.RootConfiguration.HtmlAttributes["class"] = "styled-dropdown";
        }
    }
}

The FormComponent property contains a collection of all the fields being rendered on the form during the request. In this case, we are checking each field and executing code only if it is a dropdown component. 

The if statement in the AddDropDownSpecificMarkup method is stating that if any input is a type of dropdown, then add a class of "styled-dropdown" to each RootConfiguration of that input. In the previous blog post, we already added a class of "form-group" to the RootConfiguration of every input on the form, so this class will be adding, not replacing, a value to that current class attribute. 

3.  Once the method  is created, then you need to call it in the InjectMarkupIntoKenticoComponents method
private static void InjectMarkupIntoKenticoComponents(object sender, GetFormFieldRenderingConfigurationEventArgs e)
{
    // Checks for Kentico form components to apply custom markup 
    if (!e.FormComponent.Definition.Identifier.StartsWith("Kentico", StringComparison.InvariantCultureIgnoreCase))
    {
            return;
    }
    // Calls class specific markup
    AddDropDownSpecificMarkup(e);
}
4. With each dropdown now having the class list of "form-group styled-dropdown" add these styles to your project to globally target each dropdown to have cross-browser friendly styles. These styles give an after pseudo element to the dropdown container that will apply a chevron down arrow that will render the same UX on all major browsers. 
.form-group {
    &.styled-dropdown {
        select {
            -webkit-appearance: none;
            cursor: pointer;
        }

        &:after {
            font-size: 18px;
            background-image: url('https://upload.wikimedia.org/wikipedia/commons/f/f5/Chevron_down_font_awesome.svg');
            background-repeat: no-repeat;
            background-size: 20px;
            bottom: 20px;
            color: #3cb4e5;
            content: "";
            display: block;
            height: 15px;
            pointer-events: none;
            position: absolute;
            right: 15px;
            width: 20px;
        }
        // IE override to hide browser specific arrow
        ::-ms-expand {
            display: none;
        }
    }
}

Your form dropdowns should now look like this and have a nice chevron arrow that will override each browser default dropdown arrow style. 

Example of form with chevron arrow

Applying Accessibility and Required Field Attributes

Now that you have one class implemented and running successfully in our FormBuilderContextualConfig.cs static class, you can keep utilizing these properties to add contextual styling to your form. In the next example, we will be rendering asterisks on the required field’s labels based on the condition of if they are required or not. 

1. Create a new private method AddAccessibilityAttributes, and pass in the GetFormFieldRenderingConfigurationEventArgs event to get access to various properties. Like the previous example, we will be using the  FormComponent property.

2. Add check to your method for targeting if an input is required and add the following code to your if statement.

private static void AddAccessibilityAttributes(GetFormFieldRenderingConfigurationEventArgs e)
{
    if (e.FormComponent.BaseProperties.Required)
    {
        // Adds the 'aria-required' and 'required' attributes to the component's 'input' element
        e.Configuration.EditorHtmlAttributes["aria-required"] = "true";

        if (e.Configuration.LabelHtmlAttributes.ContainsKey("class"))
        {
            e.Configuration.LabelHtmlAttributes["class"] += " required";
        }
        else
        {
            e.Configuration.LabelHtmlAttributes["class"] = "required";
        }
    }
}
3. Once the method  is created, then you need to call it in the InjectMarkupIntoKenticoComponents method
private static void InjectMarkupIntoKenticoComponents(object sender, GetFormFieldRenderingConfigurationEventArgs e)
{
    // Checks for Kentico form components to apply custom markup 
    if (!e.FormComponent.Definition.Identifier.StartsWith("Kentico", StringComparison.InvariantCultureIgnoreCase))
    {
        return;
    }
    // Calls class specific markup
    AddDropDownSpecificMarkup(e);
    AddAccessibilityAttributes(e);
}

4. This custom method adds a class to each label of a required field of "required". Instead of having to add the asterisk directly to the label in the Kentico Form Builder, you can add a styled asterisk to each required label. This will visually give your user a queue that the field is required, and give you as the developer full control on what this will look like with a few lines of SCSS.
.required::after {
    content: "*";
    color: #ff0000;
}

Your form should now look something like this 

Form builder with styled asterisk

Now you are left with a form with custom styles and classes that are applied on render of your form based on contextual information we check in the custom classes. This final example will show you how to work with retrieving the value of each input on render. 

Capturing The Value of an Input On Render

By now it should be pretty standard on how to add a new custom method and call it in your FormBuilderContextualConfig.cs file. This example will not have any visual changes but will allow you to capture the value of input on load and on render (for this example, on submit) of a form. This will be a great example of when to hook into the on submit action and apply custom styles or show and hide contextual content based on if a field is required and it does not have a value on submit. 

1. Create a new private method AddHasValueClass and pass in the GetFormFieldRenderingConfigurationEventArgs event to get access to various properties. Like the previous example, we will be using the  FormComponent property.

2. Create a variable to capture e.FormComponent.GetObjectValue();. This variable will look for the value of any input on render.  

3. Add a check to see if that variable is null on render. You can also add another check for if the field is required as well. In this example, we will just be capturing if there is a value for any field on the form. In the check, add a “has-value” class to that field’s RootConfiguration that has a value on render. 

private static void AddHasValueClass(GetFormFieldRenderingConfigurationEventArgs e)
{
    var formValue = e.FormComponent.GetObjectValue();

    if (!string.IsNullOrEmpty(formValue?.ToString()))
    {
        if (e.Configuration.RootConfiguration.HtmlAttributes.ContainsKey("class"))
        {
            e.Configuration.RootConfiguration.HtmlAttributes["class"] += " has-value";
        }
        else
        {
            e.Configuration.RootConfiguration.HtmlAttributes["class"] = "has-value";
        }
    }
}

4. Once the method  is created, then you need to call it in the InjectMarkupIntoKenticoComponents method
private static void InjectMarkupIntoKenticoComponents(object sender, GetFormFieldRenderingConfigurationEventArgs e)
{
    // Checks for Kentico form components to apply custom markup 
    if (!e.FormComponent.Definition.Identifier.StartsWith("Kentico", StringComparison.InvariantCultureIgnoreCase))
    {
        return;
    }
    // Calls class specific markup
    AddDropDownSpecificMarkup(e);
    AddAccessibilityAttributes(e);
    AddHasValueClass(e);
}
You now will have contextually rendered HTML that will dynamically add a class to a field that has a value. You can work with this class in many ways to have full control over what needs to happen, or what needs to be styled when a field does or does not have a value.

The Benefits

Fin! Having full control of your rendered forms HTML markup is something that is very beneficial and useful when it comes to clean and reusable code without the bloat. Now adding the concept of contextually modifying form markup on render has its own set of benefits on top of generic HTML markup control.

You now have the ability to create a specific custom method to handle certain scenarios you want to capture on the fly when your form is getting rendered. It not only helps the user experience but for the usability of customization you have as a developer as well. 

With adding a simple custom method to your FormBuilderContextualConfig.cs file and calling it in your Global.asax on initialization, the world is your oyster when it comes to customization and control. By applying what part one of this series has gone over as far as form HTML customization, as well as new concepts of contextually modifying the markup, you now have full control of your forms you create with Kentico 12’s Form Builder.  

Tell us what you think when it comes to Kentico 12’s Form Builder. Do you find these customizations useful when creating your custom forms? Do you have any tips and tricks to tack on to what both of these articles have covered? Let me know in the comments below.

Share This Post:

Twitter Pinterest Facebook Google+
Click here to read more Kentico posts
Start a Project with Us
Photo of the author, Shelby Tieche

About the author

When Shelby was thirteen she didn’t realize that the hours she spent staying up late building themes and layouts for MySpace and Xanga pages would later inspire her future career choice. As a recent grad from Michigan State and an even more recent Texas transplant, she now applies her knowledge to the front-end development team at BizStream. Shelby is excited to be back in the Grand Rapids area where she frequents music venues and local breweries.

View other posts by Shelby

Subscribe to Updates

Stay up to date on what BizStream is doing and keep in the loop on the latest with Kentico.