• Published
  • 3 min

Creating custom form elements in Episerver.Forms

With the new Episerver.Forms, you get the opportunity to create your own form elements, which vastly extends the use case for them.

Disclaimer: This is based on a beta version of Episerver.Forms, so anything can change in the future. If stuff breaks after updating, you're going to have to deal with that yourself. 

Episerver provides you with a bunch of default form input elements. Textboxes, textareas, dropdown lists and number fields with suitable validators come as standard when you install the package. However, you might just need to create your own: Maybe your text field needs some funky autocomplete? Or maybe you need more markup around your field to guide your users properly? What about dynamically loaded data sources for a dropdown depending on the value in a textbox? All these things can be made.

1. Your custom form element type

Since form elements are based on blocks, you create them the same way as any form of IContent. Where you'd normally inherit from PageData or BlockData, you will now inherit from one of the classes in the EPiServer.Forms.Implementation.Elements or EPiServer.Forms.Implementation.Elements.BaseClasses namespaces. In my example, I'm going for a custom text box:

[ContentType(GUID = "95A98808-4BFC-43FE-B723-4FD2F7E0FF1A")]
public class CustomTextBoxElementBlock : TextboxElementBlock
{
    public virtual string HelpText { get; set; }
}

So, as you can see, it's just inheriting from the existing text box, and then I'm adding an additional property, just like on other IContent types.

You currently have to provide a translated name of your content type, or you won't be able to add it to your form. This should be done by putting it in one of your language files, along with your other translations:

<languages>
  <language name="English" id="en">
    <contenttypes>
      <customtextboxelementblock>
        <name>My custom text box</name>
        <description />
      </customtextboxelementblock>
    </contenttypes>
  </language>
</languages>

2. Your view

The current version of the Forms module does not support inheriting the default views, so you'll have to create your own. This will probably be the case most of the time anyways.

@model CustomTextBoxElementBlock

<div class="Form__Element FormTextbox" data-epiforms-element-name="@Model.FormElement.Code">
    <label for="@Model.FormElement.Guid">
        My label
    </label>
    <input type="text" name="@Model.FormElement.Code" class="FormTextbox__Input" id="@Model.FormElement.Guid" @Model.FormElement.AttributesString/>

    <p>@Html.PropertyFor(x => x.HelpText)</p>

    <span data-epiforms-linked-name="@Model.FormElement.Code" class="Form__Element__ValidationError" style="display: none;">*</span>
</div>

Apart from rendering the HelpText property, this seems to be the absolute minimum required to render a custom input field properly. The class names, surrounding container and data-attributes are required for the built in client side validators to work. Apart from letting those stay, you can fiddle about with element types and adding stuff if you need to. Custom client side magic will have to be added separatly, unless you want it in the same file.

Wishes going forward

Since this is currently a beta module, here is some input for you guys making it:

  • Make the default views inheritable. Useful if you only want to hop onto specific custom element types and tweak them on the FormsSubmitting event.
  • Let us turn off the client side part of the module (to provide our own magic in some way)
  • Make it behave more like plain standard HTML forms when submitting. If you have multiple inputs with the same name, the values from all of them should be submitted to the server - not just the first. Having multiple values on the server side could enable custom elements which for instance dynamically adds multiple lines with multiple textbox-inputs and transforms them into a JSON-object in FormsSubmitting.
  • Fix requiring a translated name for adding custom elements to your forms. Shouldn't give console errors due to the form element not passing validation
  • Along with the dynamically added textboxes saved as JSON, allow custom rendering of submitted data in the Forms submissions view in edit mode.
  • Rename the Code property on IFormElemement, to something like "FieldName", "InputName", "DataFieldName" or the like - as this closer resembles the name-property in HTML which it's used for. "Code" is also "taken" in Commerce contexts, where it represents a product code/product number, so this might cause confusion.
  • Don't force the use of ~/Views/Blocks as the view locations. Solutions will follow other conventions or require more sophisticated structures than that. Should work as other view locations - possible to add more by ovveriding RazorViewEngine (or whatever view engine you're using).