Click here to Skip to main content
Click here to Skip to main content
Go to top

Bootstrap HTML Helpers

, 10 May 2013
Rate this:
Please Sign up or sign in to vote.
With the Bootstrap Helpers project I have made things even easier for .NET developers.

Introduction

The guys over at Twitter have done a serious favor for developers worldwide with their Bootstrap framework. This is especially useful for us coders with limited skills in UI design. With the Bootstrap Helpers project I have made things even easier for .NET developers.

Update (2013.05.10)

Note that the Bootstrap Helpers are now available as a Nuget package! Here is the link: https://www.nuget.org/packages/VortexSoft.Bootstrap[^]. Additionally, the project is hosted on GitHub now, as that is what most people seem to be using these days for open source projects. I am hoping this will help with contributors. Here is the link for that: https://github.com/gordon-matt/BootstrapHelpers[^]

Usage

Here are some examples of the most useful of HTML helpers using the Razor syntax.

Modal Dialog

<a class="btn" data-toggle="modal" href="#myModal" >Normal Modal</a>

@using (var modal = Html.Bootstrap().Begin(new Modal(new { id = "myModal" })))
{
    using (var header = modal.BeginHeader())
    {
        <button type="button" class="close" 
            data-dismiss="modal">×</button>
        <h3>Modal header</h3>
    }
    using (var body = modal.BeginBody())
    {
        <p>One fine body…</p>
    }
    using (var footer = modal.BeginFooter())
    {
        @Html.Bootstrap().Button("Close", BootstrapNamedColor.Default, 
              null, new { data_dismiss = "modal" })
        @Html.Bootstrap().Button("Save Changes", BootstrapNamedColor.Primary, null)
    }
}

Tabs

@using (var tabs = Html.Bootstrap().Begin(new Tabs()))
{
    tabs.Tab("Tab One", "tab1");
    tabs.Tab("Tab Two", "tab2");
    tabs.Tab("Tab Three", "tab3");

    using (tabs.BeginPanel())
    {
        <p>This is tabs panel 1 content</p>
    }
    using (tabs.BeginPanel())
    {
        <p>This is tabs panel 2 content</p>
    }
    using (tabs.BeginPanel())
    {
        <p>This is tabs panel 3 content</p>
    }
}
You could also place the tabs on the left or right. Here is an example:
@using (var tabs = Html.Bootstrap().Begin(new Tabs(TabPosition.Left)))
{
//etc
}

Accordion/Collapse

@using (var accordion = Html.Bootstrap().Begin(new Accordion("accordion1")))
{
    using (var panel = accordion.BeginPanel("Panel 1", "panel1"))
    {
        <p>This is accordion panel 1 content</p>
    }
    using (var panel = accordion.BeginPanel("Panel 2", "panel2"))
    {
        <p>This is accordion panel 2 content</p>
    }
}

Carousel

@using (var carousel = Html.Bootstrap().Begin(new Carousel("carousel1")))
{
    carousel.Item("~/Images/Red.png", "Red");

    using (var item = carousel.ItemWithCaption("~/Images/Green.png", "Green"))
    {
        <h4>This is Green</h4>
        <p>Green is a nice color</p>
    }

    carousel.Item("~/Images/Blue.png", "Blue");
}

Sub Nav

@using (var subNav = Html.Bootstrap().Begin(new SubNavBar()))
{
    subNav.Item("Modal", "#demoModal");
    subNav.Item("Tabs", "#demoTabs");
    subNav.Item("Accordion", "#demoAccordion");
    subNav.Item("Other", "#demoOther");
    subNav.Item("Toolbar", "#demoToolbar");
    subNav.Item("Thumbnails", "#demoThumbs");
    subNav.Item("Carousel", "#demoCarousel");
    subNav.Item("Code Blocks", "#demoCodeBlocks");
    subNav.Item("Forms", Url.Action("DemoForm", "Home"));

    subNav.DropDownItem("DropDown", new List<BootstrapListItem>
    {
        new BootstrapListItem { Text = "Something", Url = "#something" },
        new BootstrapListItem { Text = "Something Else", Url = "#something-else" },
        new BootstrapListItem { Text = "Yet Something More", Url = "#yet-something-more" }
    });
}

Miscellaneous

There are also many smaller helpers which you can find, such as the Buttons. Here is an example of an action button:

@Html.Bootstrap().ActionButton("Home", BootstrapNamedColor.Primary, 
             "Index", "Home")

How it was done

When building any HTML helpers, I consider it always good practice to separate them from the rest of the standard ones. So, instead of calling:

Html.BeginBootstrapAccordion()

or something like that, we want to call:

Html.Bootstrap().Begin(new Accordion())

instead. The way to do this would be to first create a class called Bootstrap with only one constructor whose accessibility is set to internal. Here is an example:

public class Bootstrap<TModel>
{
    private readonly HtmlHelper<TModel> helper;

    internal Bootstrap(HtmlHelper<TModel> helper)
    {
        this.helper = helper;
    }
//etc

You of course need to pass an instance of HtmlHelper as well and in that class is where you will add all the helper methods. Here is a simple example (with overloads):

public MvcHtmlString ActionButton(string text, BootstrapNamedColor color, string actionName, string controllerName)
{
    return ActionButton(text, color, actionName, controllerName, null);
}

public MvcHtmlString ActionButton(string text, BootstrapNamedColor color, 
       string actionName, string controllerName, object routeValues)
{
    return ActionButton(text, color, actionName, controllerName, routeValues, null);
}

public MvcHtmlString ActionButton(string text, BootstrapNamedColor color, 
       string actionName, string controllerName, object routeValues, object htmlAttributes)
{
    var builder = new TagBuilder("a");
    builder.SetInnerText(text);

    builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

    switch (color)
    {
        case BootstrapNamedColor.Important: builder.AddCssClass("btn btn-danger"); break;
        case BootstrapNamedColor.Default: builder.AddCssClass("btn"); break;
        case BootstrapNamedColor.Info: builder.AddCssClass("btn btn-info"); break;
        case BootstrapNamedColor.Inverse: builder.AddCssClass("btn btn-inverse"); break;
        case BootstrapNamedColor.Primary: builder.AddCssClass("btn btn-primary"); break;
        case BootstrapNamedColor.Success: builder.AddCssClass("btn btn-success"); break;
        case BootstrapNamedColor.Warning: builder.AddCssClass("btn btn-warning"); break;
        default: builder.AddCssClass("btn"); break;
    }

    var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
    builder.MergeAttribute("href", urlHelper.Action(actionName, controllerName, routeValues));

    return MvcHtmlString.Create(builder.ToString());
}

Finally, you need to create an instance of the Bootstrap class somewhere. Since it only has an internal constructor, you can only instantiate it from the project it is created in and since you want to be able to use it from any other project, what you do is create a public extension method in that same project like so:

public static class HtmlHelperExtensions
{
    public static Bootstrap<TModel> Bootstrap<TModel>(this HtmlHelper<TModel> htmlHelper)
    {
        return new Bootstrap<TModel>(htmlHelper);
    }
}

And as easy as that you can now add all your helper methods into the Bootstrap “we’ll call it name space; for lack of a better word”. So now I just use it like this:

@Html.Bootstrap().ActionButton("Home", BootstrapNamedColor.Primary, "Index", "Home")

Awesome! Show me more! Okay, okay, here goes: Inspect the following:

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <fieldset>
        <legend>Registration Form</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
            </li>
        </ol>
        <input type="submit" value="Register" />
    </fieldset>
}

The HTML helper in this case is BeginForm() and it is different somehow.. yes, it allows you to add HTML content in between the braces. Nice! Ever wondered how it’s done? Well, stop wondering.. let’s create our own. You basically need do create a class that inherits from IDisposable like so:

public class AccordionBuilder<TModel>
{
    protected readonly TextWriter textWriter;
    protected readonly HtmlHelper<TModel> htmlHelper;

    internal AccordionBuilder(HtmlHelper<TModel> htmlHelper, Accordion accordion)
    {
	this.htmlHelper = htmlHelper;
	this.textWriter = htmlHelper.ViewContext.Writer;
        	this.textWriter.Write(@“<div class=””acccordion””>”);
    }

    public override void Dispose()
    {
        this.textWriter.Write(@“</div>”);
    }
}

The code for the real accordion is a little more complex than the above. I have simplified the above to give you a clearer picture of what’s going on. Basically, in the constructor we write the start of the element (a <div> in this case or <form> tag in the case of Html.BeginForm()) and in the Dispose() method we write the end tag. Since the using statement automatically calls Dispose() on an IDisposable, then that’s all we need to do.. nothing too fancy here.

Final word

These helpers are there to benefit everyone. As such it is my hope that there will be those who’d like to contribute and make these helpers even better for everyone. Enjoy!

Acknowledgements

I must give credit to Attila Losonc of the jQuery UI Helpers project; it is that awesome project that inspired me to create the Bootstrap Helpers.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

gordon_matt
Software Developer VortexSoft
Vietnam Vietnam
No Biography provided

Comments and Discussions

 
QuestionFluent Syntax PinmemberDavid Sehnal21-Dec-12 5:39 
AnswerRe: Fluent Syntax Pinmembergordon_matt10-May-13 1:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140905.1 | Last Updated 10 May 2013
Article Copyright 2012 by gordon_matt
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid