C#'s TagBuilder on steroids 💪
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
HtmlBuilders.Tests
HtmlBuilders
.gitattributes
.gitignore
.travis.yml
01 - build.cmd
02 - test.cmd
03 - nuget pack.cmd
04 - nuget publish.cmd
HtmlBuilders.sln
HtmlBuilders.sln.DotSettings
License.MD
README.md
Rebracer.xml

README.md

HtmlBuilders

Build Status

C#'s TagBuilder on steroids 💪


Available as a Nuget Package!


Summary

HtmlBuilders is a mini project that aims to simplify HTML creation, parsing and manipulating. The end result is shorter, better readable and more flexible code! You could see it as a more advanced version of C#'s built-in TagBuilder.

Crash course with code snippets

Part 1: Creating HTML

What if we wanted to make this HTML in C# from within a HtmlHelper extension or tag helper?

	<div class="control-group">
		<div class="controls">
			<label class="checkbox">
				<input type="checkbox"> Remember me
			</label>
			<button type="submit" class="btn">Sign in</button>
		</div>
	</div>

Remember how you used to do this back in the days with the TagBuilder?

	var controlGroup = new TagBuilder("div");
	controlGroup.AddCssClass("control-group");
	var controls = new TagBuilder("div");
	controls.AddCssClass("controls");
	var label = new TagBuilder("label");
	label.AddCssClass("checkbox");
	var input = new TagBuilder("input");
	input.MergeAttribute("input", "checkbox");
	label.InnerHtml = input + " Remember me";
	var button = new TagBuilder("button");
	button.MergeAttribute("type", "submit");
	button.AddCssClass("btn");
	button.InnerHtml = "Sign in";
	controls.InnerHtml = label.ToString() + button;
	controlGroup.InnerHtml = controls.ToString();

Would you like some fluent syntax with that?

	var fluent = new HtmlTag("div").Class("control-group")
		.Append(new HtmlTag("div").Class("controls")
			.Append(new HtmlTag("label").Class("checkbox")
				.Append(new HtmlTag("input").Type("checkbox"))
				.Append(" Remember me")))
		.Append(new HtmlTag("button").Type("submit").Class("btn").Append("Sign in"));

Or use the HtmlTags class that provides ultrafast access to all standard HTML elements

	var fluent = HtmlTags.Div.Class("control-group")
		.Append(HtmlTags.Div.Class("controls")
			.Append(HtmlTags.Label.Class("checkbox")
				.Append(HtmlTags.Input.Checkbox)
				.Append(" Remember me")))
		.Append(HtmlTags.Button.Type("submit").Class("btn").Append("Sign in"));

Or you can just write the HTML and parse it to an HTML tag

	var parsed = HtmlTag.Parse(
		"<div class='control-group'>" +
		"  <div class='controls'>" +
		"    <label class='checkbox'><input type='checkbox'> Remember me</label>" +
		"    <button type='submit' class='btn'>Sign in</button>" +
		"  </div>" +
		"</div>"
	);

Implements IHtmlContent

HtmlTag is fully compatible with IHtmlContent, the core interface in .NET MVC and Razor. This means you can do things like this:

	@HtmlTags.Div.Id("render-straight-to-razor");
	@Html.TextBoxFor(m => m.Name).ToHtmlTag().Class("add-stuff-to-existing-MVC-things");

It's tested!

There's an extensive suite of more than 100 unit tests making sure I haven't forgotten anything. For those of you who get a kick out of juicy syntax and unit tests, here are some snippets from the tests:

	// parsing from a string!
	var div = HtmlTag.Parse("<div><a href='testhref'></a><img src='testsrc'/></div>");
	Assert.That(div.TagName, Is.EqualTo("div"));
	// Children is an IEnumerable<HtmlTag>
	Assert.That(div.Children.Count(), Is.EqualTo(2));
	
	var a = div.Children.First();
	Assert.That(a.TagName, Is.EqualTo("a"));
	Assert.That(a.HasAttribute("href"), Is.True);
	Assert.That(a["href"], Is.EqualTo("testhref"));

	var img = div.Children.Last();
	Assert.That(img.TagName, Is.EqualTo("img"));
	Assert.That(img.HasAttribute("src"), Is.True);
	Assert.That(img["src"], Is.EqualTo("testsrc"));

The API is also quite a bit richer than what you're used to from the TagBuilder, how about direct access to the style attribute:

	var div = new HtmlTag("div").Style("width", "10px").Style("height", "15px");
	Assert.That(div.HasAttribute("style"), Is.True);
	// Styles is an IReadonlyDictionary<string, string> with a getter and setter
	Assert.That(div.Styles.Count, Is.EqualTo(2));
	Assert.That(div.Styles.ContainsKey("width"), Is.True);
	Assert.That(div.Styles["width"], Is.EqualTo("10px"));
	Assert.That(div.Styles.ContainsKey("height"), Is.True);
	Assert.That(div.Styles["height"], Is.EqualTo("15px"));

There's also some extra support for data attributes

	// results in <div data-test="datatest"></div>
	new HtmlTag("div").Data("test", "datatest");
	
	// support for anonymous objects too, like what you're used to from the MVC html helpers. Attributes will be automatically prefixed with data-
	new HtmlTag("div").Data(new { test = "data test", test2 = "data test 2", test3 = "data test 3" });

HtmlTag implements IDictionary<string,string>! Thats right, every HtmlTag can be used as a dictionary to manipulate its attributes. It also allows for some language sugar:

	var div = new HtmlTag("div") {{"name", "div-name"}, {"id", "div-id"}};
	Assert.That(div.HasAttribute("name"));
	Assert.That(div.HasAttribute("id"));
	Assert.That(div["name"], Is.EqualTo("div-name"));
	Assert.That(div["id"], Is.EqualTo("div-id"));

Contributors