---
title: Create form element with validator
slug: cms-12/docs/creating-form-element-with-validator
docTags: 
createdAt: 2026-08-10T15:55:57.000Z
---

:::hint{type="info"}
**Note**
[Optimizely Forms](docId:3SbSlJZIS_3iFmghfQA3J) is only supported by MVC-based websites and HTML5-compliant browsers.
:::

Form elements inherit from an `ElementBlockBase` class, which is the only type allowed in the form element Content Area. Inherit from `ValidatableElementBlockBase` to support custom validator.

By default, you can choose from available form element validators (that inherit `ElementValidatorBase` class). If you only need some of these validators, or you have your own validator, you can include or exclude them selectively by using the `AvailableValidatorTypesAttribute` attribute. The following element includes only the `RequiredValidator` along with its validator. Apply `MyCustomValidator` to this element; do not make it available for others.

```csharp
[ContentType(GUID = "{A4EE6053-3932-4300-8B3B-7BABF9AEAB67}", GroupName = ConstantsFormsUI.FormElementGroup, Order = 2230)]
[AvailableValidatorTypesAttribute(Include = new Type[] {
  typeof (RequiredValidator)
})]
public class MyCustomElementBlock: ValidatableElementBlockBase {
  public virtual string CustomProperty {
    get;
    set;
  }

  /// 
  /// Always use a custom Validator to validate this element (along with builtin Validator RequiredValidator)
  /// The custom Validator is not visible to Editor (in EditView), but it still works to validate element value
  /// 
  [Display(GroupName = SystemTabNames.Content, Order = -5000)]
  public override string Validators {
    get {
      var customValidator = typeof (MyCustomValidator).FullName;
      var validators = this.GetPropertyValue(content => content.Validators);
      if (string.IsNullOrEmpty(validators)) {
        return customValidator;
      } else {
        return string.Concat(validators, EPiServer.Forms.Constants.RecordSeparator, customValidator);
      }
    }
    set {
      this.SetPropertyValue(content => content.Validators, value);
    }
  }
}
```

`MyCustomValidator`:

```csharp
public class MyCustomValidator: ElementValidatorBase {
  private Injected<LocalizationService> _localizationService;
  protected LocalizationService LocalizationService {
    get {
      return _localizationService.Service;
    }
  }

  public override bool ? Validate(IElementValidatable targetElement) {
    return true;
  }
  /// 
  /// return false if we don't want to show this specific-validators to Editor. This validators always work programatically for AddressElement.
  public override bool AvailableInEditView {
    get {
      return false;
    }
  }

  /// 
  public override IValidationModel BuildValidationModel(IElementValidatable targetElement) {
    var model = base.BuildValidationModel(targetElement);
    if (model != null) {
      model.Message = this.LocalizationService.GetString("/episerver/forms/validators/elementselfvalidator/unexpectedvalueisnotaccepted");
    }
    return model;
  }
}
```

Only the `RequiredValidator` appears in edit view; `MyCustomValidator` is included transparently.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/zHrdLEmdk-IhzB6nYAhsm_d2a6154-form-custom-validator-required-only.png)

You must specify a validate handler to validate a form element on the client side. `Serverside"s `Fullname`of the`Validator`instance is used as object key (case-sensitive) to lookup the`Clientside`validate function. The`EpiForm\` client code calls this function to validate the form element's value before submitting the form.

```csharp
// extend the EpiForm JavaScript API in ViewMode
$.extend(true, epi.EPiServer.Forms, {
  /// extend the Validator to validate Visitor's value in Clientside.        
  Validators: {
    "EPiServer.Forms.Samples.Implementation.Validation.MyCustomValidator": function (fieldName, fieldValue, validatorMetaData) {
      // this function is used to validate visitor's data value in ViewMode

      if (!condition) {
        return {
          isValid: false,
          message: validatorMetaData.model.message
        };
      }
      return {
        isValid: true
      };
    },
  },
})
```

### Element view

The default path of element views is found at `modules\\\_protected/EPiServer.Forms/Views/ElementBlocks`, but you can override this by adding custom views in the `Views/Shared/ElementBlocks` folder. If you want a custom view location, you can override the `GetDefaultViewLocation` method of `CustomViewLocationBase` class:

```csharp
[ServiceConfiguration(typeof (ICustomViewLocation))]
public class FormsSamplesViewLocation: CustomViewLocationBase {
  public virtual string GetDefaultViewLocation() {
    var defaultPathToBlockViews = "~" + ModuleHelper.ToResource(this.GetType(), "Views/ElementBlocks");
    return defaultPathToBlockViews;
  }
}
```

### Form element resources

If a form element needs its resource, it must implement the `IElementRequireClientResources` interface. The form element's resource is loaded after the form's resources and external's resources. For example, the `DateTime` element requires jQuery datetime to work, but it is not loaded until the element is dragged into the form. For example:

```csharp
public IEnumerable<Tuple<string, string>> GetExtraResources() {
  if (!string.IsNullOrWhiteSpace(Settings.Instance.GoogleMapsApiV3Url)) {
    var publicVirtualPath = ModuleHelper.GetPublicVirtualPath(Constants.ModuleName);
    var currentPageLanguage = FormsExtensions.GetCurrentPageLanguage();
    return new List<Tuple<string, string>>() {
      new Tuple<string, string>("script", string.Format(Settings.Instance.GoogleMapsApiV3Url, currentPageLanguage)),
        new Tuple<string, string>("script", publicVirtualPath + "/ClientResources/ViewMode/AddressesElementBlock.js")
    };
  }
  return new List<Tuple<string, string>>();
}
```

:::hint{type="info"}
**Note**
The `Constants.ModuleName` comes from `EPiServer.Forms.Samples` namespace. You can replace it with your project namespace.
:::

### Customize an element's icon and image

To display a form element's image in the Forms Element gadget, add an image with the same name as the element name inside `modules/_protected/EPiServer.Forms.UI/{version}/ClientResources/epi-forms/themes/sleek/images/contenttypes`. If you want a different location for a form element's big icons, you can override the default one (dojo part):

```csharp
var contentTypeService = dependency.resolve('epi.cms.ContentTypeService'),
  self = this;
aspect.around(contentTypeService, '_getImagePathByTypeIdentifier', function (originalFunction) {
  return function ( /*String*/ typeIdentifier, /*Array*/ registeredTypes, /*String*/ clientResourcePath) {
    var types = self._settings.registeredElementContentTypes;
    if (types instanceof Array && types.indexOf(typeIdentifier) >= 0) {
      // show the .png as big icon for creating FormElement in the ContentArea
      return self._settings.clientResourcePath + '/ClientResources/epi-formssamples/themes/sleek/images/contenttypes/' + typeIdentifier.split('.').pop() + '.png';
    }
    return originalFunction.apply(contentTypeService, arguments);
  };
});
```

From Optimizely Forms 4.4.2, you can use the `ImageUrl` attribute to change the big icon of a form element block like other block types by adding this to the custom element block:

```csharp
[ImageUrl("~/static/img/thumbnails/CustomTextArea.png")]
```

For the small icon in the Form Elements gadget, add a class as follows:

```csharp
.epi-forms-icon.epi-forms-icon--small.epi-forms-mycustomelementblock__icon {
  background:url(images/mycustomelemeticon.png) 0px 0px no-repeat
}
```

For examples of custom form elements, see [https://github.com/episerver/EPiServer.Forms.Samples](https://github.com/episerver/EPiServer.Forms.Samples).
