Semantic markup with EPiServer XForms

Posted on November 26, 2010 by Frederik Vig in EPiServer

EPiServer’s XForm editor is used for letting editors easily build forms inside EPiServer. The HTML markup that XForm renders uses tables to layout the form. Semantically this is completely wrong, so in this post I’m going to show you how easy it is to replace the HTML markup rendered by XForms with your own.

Before we start I recommend reading the tech-note: Developing with XForms.

There are two ways to override the rendering of XForms. We can use the BeforeLoadingFormsEvent event or the ControlsCreated event (see the tech-note for more information)

Coding time

Open up Global.asax.cs – here you’ll find methods that are already attached to various XForm events. Go to the method XForm_ControlsCreated and add this code at the bottom, inside the method.

public void XForm_ControlsCreated(object sender, EventArgs e)
{
    ...
    this.CleanupXFormHtmlMarkup(formControl);
}

Now we need to create the CleanupXFormHtmlMarkup method.

private void CleanupXFormHtmlMarkup(XFormControl formControl)
{
}

Before we start coding away, let’s decide on the markup we’d like to have.

<div class="xform>
<fieldset>
<p>
<label for="name">Name:</label>
<input type="text" id="name" name="name" size="20" value="" />
</p>
...
</fieldset>
</div>

After reading the tech-note we know that all the LiteralControls in the Control collection contain the table markup for the form. What we need to do is traverse through the Control collection and replace this markup with our own.

private void CleanupXFormHtmlMarkup(XFormControl formControl)
{
	if (formControl.EditMode)
	{
		// We need to render the default table when in edit mode, otherwise the form wizard won't work
		return;
	}
 
	bool firstLiteralControl = false;
	LiteralControl literalControl = null;
 
	ControlCollection controls = formControl.Controls;
 
	foreach (object control in controls)
	{
		if (control is LiteralControl)
		{
			literalControl = control as LiteralControl;
 
			// find the first literal control
			if (!firstLiteralControl)
			{
				literalControl.Text = "<fieldset><p>";
				firstLiteralControl = true;
			}
			else
			{
				literalControl.Text = "</p><p>";
			}
		}
	}
 
	// update markup for the last literal control
	if (literalControl != null)
	{
		literalControl.Text = "</p></fieldset>";
	}
}

Here’s the HTML markup rendered for the Public Template’s contact form after our updates:

<div id="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormPanel" class="xForm">
	<fieldset>
		<p>
			<label for="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Name">
				Your name:</label><input type="text" class="value" title="Your name" id="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Name"
					name="ctl00$MainRegion$MainContentRegion$MainBodyRegion$ctl01$FormControl$Name"
					value="" />
		</p>
		<p>
			<label for="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Email">
				Your e-mail address:</label><input type="text" class="value" title="Your e-mail address"
					id="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Email"
					name="ctl00$MainRegion$MainContentRegion$MainBodyRegion$ctl01$FormControl$Email"
					value="" />
		</p>
		<p>
			<label for="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Message">
				Your message:</label><textarea class="textbox" title="Enter your messgage here" id="ctl00_MainRegion_MainContentRegion_MainBodyRegion_ctl01_FormControl_Message"
					name="ctl00$MainRegion$MainContentRegion$MainBodyRegion$ctl01$FormControl$Message"
					cols="20" rows="2"></textarea>
		</p>
		<p>
			<input type="submit" value="Send" name="ctl00$MainRegion$MainContentRegion$MainBodyRegion$ctl01$FormControl$ctl00"
				class="button" title="Send you message" onclick="WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl00$MainRegion$MainContentRegion$MainBodyRegion$ctl01$FormControl$ctl00&quot;, &quot;&quot;, false, &quot;XForm&quot;, &quot;&quot;, false, false))" />
		</p>
	</fieldset>
</div>

With only a few code changes we easily changed all the XForm HTML markup. We could also customize validation (we have access to all the controls) and the form even more, but that is for another post :).

Related Posts: