Using .NET validators can be a friendly shortcut for developers but also a nuisance when you start incorporating multiple validators (RequiredFieldValidator, RegularExpressionValidator, CompareValidator, etc.) per form control. A challenge I recently faced was styling an invalid form control with multiple validators, and was able to solve the issue with simple JavaScript and CSS.

Styling Form Controls with One Validator

If you only have one validator per form control, and the validation control has setting Display = Dynamic or Static and is immediately before the form control, you can just use CSS. For example:

<style>
	/* 
		Style the form control immediately following the invalid validator.
		span.validator[style*=inline] takes care of validators with Display="Dynamic"
		span.validator[style*=visible] takes care of validators with Display="Static"
	*/
	span.validator[style*=inline] + .form-control,
	span.validator[style*=visible] + .form-control { 
		border:1px solid #d43f3a;
	}
</style>
<form id="form1" runat="server">
	<div class="col-xs-3 form-group">
		
		<label for="ddlCssExample">CSS Example</label>
		
		<span class="help-block">(RequiredFieldValidator - Before DropDownList)</span>
		
		<asp:RequiredFieldValidator ID="reqCssExample" runat="server" CssClass="validator"
			ControlToValidate="ddlCssExample" EnableClientScript="true" Enabled="true" 
			Display="Dynamic" InitialValue="" Text="" ErrorMessage="CSS Example is required" />
		
		<asp:DropDownList ID="ddlCssExample" runat="server" CssClass="form-control sm-field" /> 
		
	</div>
</form>

Styling Form Controls with Multiple Validators

If your form control has multiple validators or perhaps you need to display the validators and their error messages after the form control, you’ll need to use a combination of CSS and JavaScript to customize the style of the form control. A third (and more time consuming) option would be to create CustomValidators that combine the logic of the multiple validators you are using, but we are not covering that in this tutorial.

ASP.NET web forms use a JavaScript framework for client side validation, so we need to override the JavaScript function ValidatorUpdateDisplay to add or remove the custom CSS class invalid on the form control dependent on the number of invalid validators. This last bit is crucial for form controls with multiple validators; otherwise, the custom CSS class will be removed from the form control when the last validator that was checked was valid (even if another validator was invalid).

<style>
	.form-control.invalid { 
		border:1px solid #d43f3a;
	}
</style>
<form id="form1" runat="server">
	<div id="instructions" class="form-group">
		Select three numbers so Example 1 < Example 2 < Example 3
	</div>
	<div class="row">
		<div class="col-lg-3 col-md-4 col-xs-12 form-group">
			<label for="ddlExample1">Example 1</label>
			<span class="help-block">(RequiredFieldValidator)</span>
			<asp:DropDownList ID="ddlExample1" runat="server" CssClass="form-control sm-field" />
			<asp:RequiredFieldValidator ID="reqExample1" runat="server" CssClass="validator"
				ControlToValidate="ddlExample1" EnableClientScript="true" Enabled="true"
				Display="Dynamic" InitialValue="" Text="" ErrorMessage="Example 1 is required" />
		</div>
		<div class="col-lg-3 col-md-4 col-xs-12 form-group">
			<label for="ddlExample2">Example 2</label>
			<span class="help-block">(RequiredFieldValidator, CompareValidator)</span>
			<asp:DropDownList ID="ddlExample2" runat="server" CssClass="form-control sm-field" />
			<asp:RequiredFieldValidator ID="reqExample2" runat="server" CssClass="validator"
				ControlToValidate="ddlExample2" EnableClientScript="true" Enabled="true"
				Display="Dynamic" InitialValue="" Text="" ErrorMessage="Example 2 is required" />
			<asp:CompareValidator ID="cmpExamples12" runat="server" CssClass="validator" 
				ControlToValidate="ddlExample2" ControlToCompare="ddlExample1" 
				EnableClientScript="true" Enabled="true" Display="Dynamic" 
				Text="" ErrorMessage="Example 2 must be greater than Example 1"
				CultureInvariantValues="true" Type="Integer" Operator="GreaterThan" />
		</div>
		<div class="col-lg-3 col-md-4 col-xs-12 form-group">
			<label for="ddlExample3">Example 3</label>
			<span class="help-block">(RequiredFieldValidator, CompareValidator)</span>
			<asp:DropDownList ID="ddlExample3" runat="server" CssClass="form-control sm-field" />
			<asp:RequiredFieldValidator ID="reqExample3" runat="server" CssClass="validator" 
				ControlToValidate="ddlExample3" EnableClientScript="true" Enabled="true" 
				Display="Dynamic" InitialValue="" Text="" ErrorMessage="Example 3 is required" />
			<asp:CompareValidator ID="cmpExamples23" runat="server" CssClass="validator"
				ControlToValidate="ddlExample3" ControlToCompare="ddlExample2" 
				EnableClientScript="true" Enabled="true" Display="Dynamic"
				Text="" ErrorMessage="Example 3 must be greater than Example 2"
				CultureInvariantValues="true" Type="Integer" Operator="GreaterThan" />
		</div>
	</div>
	<div class="row">
		<div class="col-lg-9 col-md-12 col-xs-12 form-group text-right">
			<asp:Button ID="btnValidate" runat="server" CssClass="btn btn-danger" Text="Validate" 
				OnClick="btnValidate_Click" CausesValidation="true" />
		</div>
	</div>
</form>

Be sure to include your scripts at the end of the page (after </form> and before </body>). Also take note of the jQuery reference.

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">

	// Override .Net ValidatorUpdateDisplay method
	function ValidatorUpdateDisplay(val) {
		// Show or hide the validator depending on validity
		if (typeof (val.display) == "string" && val.display == "Dynamic") {
			val.style.display = val.isvalid ? "none" : "inline";
		}
		val.style.visibility = val.isvalid ? "hidden" : "visible";

		// Get the control
		var $controlToValidate = jQuery("#" + val.controltovalidate);

		// Controls may have multiple validators (e.g. RequiredFieldValidator and CompareValidator) 
		// so we need to handle the control's css class accordingly
		if (val.isvalid) {
			// Get all invalid (visible) validators for this control
			var $otherValidators = $controlToValidate.siblings("span.validator").filter(function () {
				return $(this).css('visibility') == 'visible';
			});
			// Only remove the invalid class if there are no other invalid validators for this control
			if ($otherValidators.length == 0)
				$controlToValidate.removeClass("invalid");
		}
		else {
			// Current validator is invalid so add our css class
			$controlToValidate.addClass("invalid");
		}
	}

</script>