Click here to Skip to main content
Full site     10M members (37.2K online)    

TwitterBootstrapMvc

Twitter Bootstrap MVC

Introduction

This project aims to help .NET MVC developers to write twitter bootstrap related code faster. If you'd like a jump start, watch 6 minutes video either on YouTube or on CodeProject.tv explaining what TwitterBootstrapMVC does.

If you like this project, please up vote it on StackOverflow. 

Background

Twitter Bootstrap is a great front-end framework and the documentation for this product is outstanding. Every use case is very well documented and is available for the developer.

The problem that I encountered with it when I was working on PersonalityMatch was that I cannot possibly memorize all this documentation. Especially this was true during writing of forms. I cannot remember how I should structure inputs and what classes I should apply to them in every situation. Even though the documentation is very well structured, it is time consuming to go through it and find the example you need.

This is why I have created this library of html extensions that aims to make writing Twitter Bootstrap related code easier. Please note that this library does not have a helper for every little thing that Twitter Bootstrap offers. Some of the components of the Bootstrap framework are very flexible in their nature, which is why writing helpers to handle these would probably force developer go to this page and see the documentation on the syntax, which would defeat the purpose of this library. 

I welcome suggestions on improving this library.

Installation

  1. Find and install "TwitterBootstrapMVC" in your project using Nuget Manager
  2. In the web.config file under Views folder include namespace="TwitterBootstrapMVC"
  3. Reload the project

Using the code

In order to use TwitterBootstrapMVC you have to be familiar with the general way Twitter Bootstrap works and with what it has to offer.

This library includes two versions of each input html helper just like there are two versions of regular MVC HTML helpers @Html.TextBoxFor(m => m.FirstName) and @Html.TextBox("FirstName"). For the sake of simplicity I will be showing examples using TextBoxFor(...).

Basic Inputs

@Html.Bootstrap().LabelFor(x => x.UserName)
@Html.Bootstrap().TextBoxFor(m => m.UserName)
@Html.Bootstrap().PasswordFor(m => m.Password)
@Html.Bootstrap().FileFor(m => m.File)
@Html.Bootstrap().CheckBoxFor(m => m.IsActivated)
@Html.Bootstrap().RadioButtonFor(m => m.Gender, "male")
@Html.Bootstrap().DropDownListFor(m => m.State, Model.UsaStates)
@Html.Bootstrap().TextAreaFor(m => m.Description)

One might say: "These look exactly like regular MVC helpers. Why were they created in the first place?" Each bootstrap input usually has a special class associated with it. This is especially true when inputs are coupled with labels (Ex: checkbox). You will never need to look at the documentation to see what class you need to apply to an input or a label. Also these methods will allow for fluent syntax which is discussed next.

Fluent syntax (chaining)

Each html helper can be customized by the use of fluent syntax.

@Html.Bootstrap().LabelFor(x => x.Amount).LabelText("Amount Left").ShowRequiredStar(true)
@Html.Bootstrap().TextBoxFor(m => m.Amount).Placeholder("amount in dollars").Prepend(
              "$").Append(".00").Append(Html.Bootstrap().Button().Text("Save"))

These two lines of code above will give you the following HTML output:

<label for="Amount">
    Amount Left<span class="required">*</span>
</label>
<div class="input-prepend input-append">
    <span class="add-on">$</span>
    <input id="Amount" name="Amount" placeholder="amount in dollars" type="text" value="10">
    <span class="add-on">.00</span>
    <button class="btn" type="button">Save</button>
</div>

Which will look like this:

example output

Labels

Each input html helper can be extended with .Label(). Once you apply it to the basic input, this input will now be coupled with the label. This will start a new chain in your fluent syntax so that before this method all the extension methods belong to the input and after this method all the extension methods belong to the label.

@Html.Bootstrap().TextBoxFor(m => m.UserName).Size(
          InputSize.Medium).Label().HtmlAttributes(new { @class = "special-label" })

Control Group and Forms

This is the section which, in my opinion brings the most value to a developer.

Often a tabular type of a form layout is needed where labels are to the left of the inputs and are aligned to each other. This is where you can use @Html.Bootstrap().ControlGroup(). Please note that you need a form with a class "form-horizontal" in order for it to display properly.

@using (Html.BeginForm("actionName", "controllerName", FormMethod.Post, new { @class = "form-horizontal" }))
{
    @Html.Bootstrap().ControlGroup().TextBoxFor(m => m.UserName)
    @Html.Bootstrap().ControlGroup().TextBoxFor(m => m.FirstName)
    @Html.Bootstrap().ControlGroup().TextBoxFor(m => m.LastName)
    @Html.Bootstrap().ControlGroup().CheckBoxFor(m => m.IsActivated)
    @Html.Bootstrap().ControlGroup().DropDownListFor(m => m.State, Model.UsaStates)
    @Html.Bootstrap().ControlGroup().TextAreaFor(m => m.Description)
	
    using(Html.Bootstrap().Container().BeginFormActions())
    {
        <div>
            @Html.Bootstrap().SubmitButton()
            @Html.Bootstrap().ActionLinkButton("Go Back", "previousAction", "controller")
        </div>
    }
}

This will give you a nice formatted form. I won't post the html output. It is more than I ever want to see or especially type. However, for the end user it will look like this:

example two

Notice that you do not need to use .Label() on each input when you are using .ControlGroup() unless you want to customize the label. Label will be created automatically. All the rules described previously apply to the ControlGroup helper methods.

In the example above I've also introduced a disposable .Bootstrap().Container().BeginFormActions(). You can put any html inside the curvy brackets there. The output in this case will be:

<div class="form-actions">
    <button class="btn" type="submit">Submit</button>
    <a class="btn" href="http://www.codeproject.com/controller/previousAction">Go Back</a>
</div>

As you can see I've also used there methods .Bootstrap().SubmitButton() and .Bootstrap().ActionLinkButton(...). These are also designed so that you don't have to lookup classes specific to your particular case. More about these below.

Placeholder

Chaining method .Placeholder() is available on TextBoxFor method. You can specify the text of the placeholder by either passing it as parameter:
@Html.Bootstrap().TextBoxFor(m =< m.UserName).Placeholder("Text for placeholder")

... or by using parameterless overload: .Placeholder() and using data annotation [Display].

So if you have the following decorated property:

[Display(Name = "Label for User Name", Prompt = "Placeholder for User Name")]
public string UserName { get; set; }
... and the this code in the view:
@Html.Bootstrap().ControlGroup().TextBoxFor(m => m.UserName).Placeholder()
... you will receive such output:
<div class="control-group">
    <label class="control-label" for="UserName">
        Label for User Name
        <span class="required" style="visibility:hidden;">*</span>
    </label>
    <div class="controls">
        <input id="UserName" name="UserName" placeholder="Placeholder for User Name" type="text" value="">
        <span class="help-inline">
            <span class="field-validation-valid" data-valmsg-for="UserName" data-valmsg-replace="true"></span>
        </span>
    </div>
</div>
Notice that Label text is "Label for User Name" and placeholder text is "Placeholder for User Name".

Buttons and Links

.ActionLinkButton is a regular link with a specific bootstrap class that makes it look like a button. It has most of the regular overloads. It also has overloads that support T4MVC, which is why TwitterBootstrapMVC depends on T4MVCExtensions.dll. I just love T4MVC so much that could not leave it out.

There is also .Bootstrap().Button() and .Bootstrap().SubmitButton() methods. The only real difference between them is that the second one has type="submit" on it. All of these three methods have the following extension methods in common:

.Id(string id)
.Size(ButtonSize size)
.Style(ButtonStyle style)
.IconPrepend(Icons icon) and .IconPrepend(Icons icon, bool isWhite)
.IconAppend(Icons icon) and .IconAppend(Icons icon, bool isWhite)

An example of appending an Icon is below:

@Html.Bootstrap().Button().Text("Cool button").IconAppend(Icons.camera)

Button Toolbars and Groups

In order to create button toolbars and button groups we can use disposable .Bootstrap().Container() again.

@using(Html.Bootstrap().Container().ButtonToolBar())
{
    using (Html.Bootstrap().Container().ButtonGroup())
    {
        @Html.Bootstrap().Button().Text("btn1")
        @Html.Bootstrap().Button().Text("btn2")
    }
    using (Html.Bootstrap().Container().ButtonGroup())
    {
        @Html.Bootstrap().Button().Text("btn3")
        @Html.Bootstrap().Button().Text("btn4")
    }
}

Dropdown Menus

According to Bootstrap's documentation, a drop down menu must be encapsulated into a button group. Inside it should have a button that triggers drop down event and the drop down menu itself. Lets recreate this structure with TwitterBoostrapMVC:

@using(Html.Bootstrap().Container().ButtonGroup())
{
    @Html.Bootstrap().Button().Text("Trigger Drop down").DropDownToggle()
    @Html.Bootstrap().DropDownMenu().MenuItems(menu => {
        menu.MenuItem(Html.ActionLink("menu item1", "action1"));
        menu.MenuItem(Html.ActionLink("menu item2", "action2"))
            .DropDownMenu().MenuItems(submenu => {
                submenu.MenuItem("<a href='http://www.personalitymatch.net' target='_blank'>PersonalityMatch</a>");
                submenu.MenuItem(Html.ActionLink("submenu item2", "action4"));
            });
        menu.Divider();
        menu.MenuItem(Html.ActionLink("menu item3", "action3"));
    })
}

Each MenuItem accepts either MvcHtmlString (in order to use regular @Html.ActionLink) or regular string (In case you want to have a link to an external resource). Also each MenuItem can have a submenu as shown in example above.

Note, I feel that implementation of Dropdown menus is already getting closer to these situations when a developer will have to come to this page to see how it needs to be used, which is why I was hesitant to implement it, but I did anyway to see what kind of feedback I get.

Help Text

Bootstrap provides a way for you to add description to the input by the means of the following markup:

<span class="help-block">Example block-level help text here.</span>

I have created a helper for that as well:

@Html.Bootstrap().HelpText("text", HelpTextStyle.Inline)

This helper also exists on every basic input for you to easily attach descriptions to the inputs if needed. I've also used this mechanism to display validation error messages for the inputs. In case you do not want to display error messages next to the input, you can use the following syntax:

@Html.Bootstrap().ControlGroup().TextBoxFor(m => m.UserName).ShowValidationMessage(false)

Tooltip and Popover

All input helpers have another extension helpers: .Tooltip(string text) and .Popover(string title, string content). They are used to put appropriate attributes on the input in order for Bootstrap tooltip or Bootstrap popover to show up.

There is one catch though. Tooltips and Popovers require a bit of JavaScript in order for it to be triggered. Include the following on the $(document).ready(...) function of your main script and you won't need to ever worry about writing any JavaScript for a given tooltip.

$('[rel=tooltip]').tooltip();
$('[rel=popover]').popover();

Please note that if you are loading content that contains tooltips or popovers via ajax, you will need to run this JavaScript code again.

Example of usage:

Tooltip:

@Html.Bootstrap().ControlGroup().TextBoxFor(x => x.UserName).Tooltip("This is an awesome tooltip!")

Advanced version of popover.

@Html.Bootstrap().Icon(Icons.info_sign).Popover(new PopoverConfiguration(
  "Info <span class='pull-right close'>X</span>","<p>This is an awesome popover!</p>") { Html = true })

Include the following JavaScript code to handle closing on the popover when "X" is clicked.

$(document).on('click', '.close', function () {
    $(this).closest('.popover').prev('[rel=popover]').popover('hide');
});

Advanced Inputs

Consider this as a bonus. My experience shows that a developer is often asked to create a list of checkboxes or radio buttons for the website. MVC does not have html helpers to support this kind of a need. This is why I've created these helpers to address this issue. 

An inspiration for these two helpers (as well as a bit of code) was another library called CheckBoxList(For) - A missing MVC extension written by  - a huge thanks to him! 

Input Lists From IEnumerable<T>: 

@Html.Bootstrap().CheckBoxListFor(m => m.CarsDriven, m => m.AllCars, car => car.Id, car => car.Name)
@Html.Bootstrap().RadioButtonListFor(m => m.CarsDriven, m => m.AllCars, car => car.Id, car => car.Name)

The constructor for both of these helpers takes four required parameters:

  1. Expression where you specify the model parameter where selected value(s) will be stored. This could be either int/string if you are doing radio buttons or IEnumerable<int/string> if you are doing checkboxes.
  2. Data Source expression - IEnumerable<T>
  3. Value Expression - select which property of <T> will be used for the value of the checkbox/radiobutton
  4. Text Expression - select which property of <T> will be used for the display text of the checkbox/radiobutton

The following chaining methods are available:

@Html.Bootstrap().CheckBoxListFor(...)
    .SelectedValues(dataSource => dataSource.Selected)                            // specify which checkboxes are selected
    .DisabledValues(dataSource => dataSource.Disabled)                            // specify which checkboxes are disabled
    .InputHtmlAttributes(dataSource => new { @class = dataSource.SomeProperty })  // customize html attributes per checkbox input
    .LabelHtmlAttributes(dataSource => new { @class = dataSource.SomeProperty })  // customize html attributes per checkbox label
    .DisplayInColumns(int numberOfColumns, int columnPixelWidth)                  // lets you display inputs in columns with specified width
    .Label()                                                                      // Customize the main label for the group of checkboxes

Input Lists From Enum:

@Html.Bootstrap().RadioButtonsFromEnumFor(m => m.SomeEnum)
@Html.Bootstrap().CheckBoxesFromEnumFor(m => m.SomeEnum)

@Html.Bootstrap().ControlGroup().RadioButtonsFromEnumFor(m => m.SomeEnum)
@Html.Bootstrap().ControlGroup().CheckBoxesFromEnumFor(m => m.SomeEnum)
All of them have the following chaining methods:
.DisplayInColumns(int numberOfColumns, int columnPixelWidth)
.DisplayInColumns(int numberOfColumns, int columnPixelWidth, bool condition)
.DisplayInlineBlock(int marginRightPx = 0)

Under the hood they use the same rendering methods as methods .CheckBoxListFor(...) and .RadioButtonListFor(...), so the output html elements will have the same classes.

You can decorate enum values with either a [Description("cool enum")] or a [Display(Name = "cool enum")] attributes. Associated with the input label will understand any of these two. 

True/False Inputs:

Also often I was asked to create a "Yes/No" or "True/False" type of radio button scenario for a boolean property. For this case I've written the following helper.

@Html.Bootstrap().RadioButtonTrueFalseFor(m => m.IsActivated)

The following chaining methods are available to customize the output:

.HtmlAttributesInputTrue(object htmlAttributes)    // specify html attributes for the true/yes input
.HtmlAttributesInputFalse(object htmlAttributes)   // specify html attributes for the false/no input
.HtmlAttributesLabelTrue(object htmlAttributes)    // specify html attributes for the true/yes label
.HtmlAttributesLabelFalse(object htmlAttributes)   // specify html attributes for the false/no label
.InputLabelsText(strig trueText, string falseText) // modify text for true and false labels
.InputsValues(object trueValue, object falseValue) // modify values for true and false inputs

History

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search 
Per page   
QuestionViews in Web.config?
Member 9040137
13hrs 31mins ago 
AnswerRe: Views in Web.config?
Dmitry A. Efimenko
13hrs 12mins ago 
GeneralRe: Views in Web.config?
Member 9040137
12hrs 59mins ago 
QuestionMy vote of 5
Abhishek Nandy
14hrs 43mins ago 
QuestionSample
bart_dk
11 May '13 - 23:19 
AnswerRe: Sample
Dmitry A. Efimenko
12 May '13 - 15:45 
GeneralMy vote of 5
Mihai MOGA
10 May '13 - 18:19 
GeneralMy vote of 5
csharpbd
8 May '13 - 0:44 
GeneralMy vote of 5
Olivier Giulieri
7 May '13 - 17:42 
GeneralMy vote of 5
Mikhail Tsennykh
7 May '13 - 4:55 
GeneralNice work!
mrchief_2000
6 May '13 - 6:36 
GeneralMy vote of 5
Renju Vinod
6 May '13 - 0:59 
QuestionValidation Question
Martijn Hoedeman
5 May '13 - 23:29 
AnswerRe: Validation Question
Dmitry A. Efimenko
6 May '13 - 10:54 
GeneralRe: Validation Question
Martijn Hoedeman
6 May '13 - 12:15 
GeneralMy vote of 5
Sunnykumar08
4 May '13 - 1:34 
GeneralNice
db7uk
3 May '13 - 0:43 
GeneralRe: Nice
Dmitry A. Efimenko
3 May '13 - 6:58 
QuestionMultiple custom controls?
tippmar
26 Apr '13 - 5:59 
AnswerRe: Multiple custom controls?
Dmitry A. Efimenko
26 Apr '13 - 8:29 
GeneralRe: Multiple custom controls?
tippmar
26 Apr '13 - 11:03 
GeneralMy vote of 5
Abinash Bishoyi
25 Apr '13 - 22:17 
Question.CustomControls() but use label from the model?
tippmar
25 Apr '13 - 10:45 
AnswerRe: .CustomControls() but use label from the model?
tippmar
25 Apr '13 - 10:53 
GeneralRe: .CustomControls() but use label from the model?
Dmitry A. Efimenko
25 Apr '13 - 11:11 
GeneralRe: .CustomControls() but use label from the model?
tippmar
25 Apr '13 - 11:37 
AnswerRe: .CustomControls() but use label from the model?
Dmitry A. Efimenko
25 Apr '13 - 18:44 
GeneralRe: .CustomControls() but use label from the model?
tippmar
26 Apr '13 - 3:48 
SuggestionVideo
GeekBond
25 Apr '13 - 7:35 
GeneralRe: Video
Dmitry A. Efimenko
29 Apr '13 - 23:33 
GeneralRe: Video
GeekBond
1 May '13 - 1:54 
SuggestionHow about .RadioButtonForEnum() ?
nw0l
25 Apr '13 - 5:57 
AnswerRe: How about .RadioButtonForEnum() ?
Dmitry A. Efimenko
25 Apr '13 - 19:28 
GeneralRe: How about .RadioButtonForEnum() ? [modified]
tippmar
26 Apr '13 - 3:47 
AnswerRe: How about .RadioButtonForEnum() ?
Dmitry A. Efimenko
26 Apr '13 - 8:31 
GeneralRe: How about .RadioButtonForEnum() ?
tippmar
26 Apr '13 - 11:03 
BugWell done!
NinjaFish
23 Apr '13 - 3:56 
GeneralRe: Well done!
Dmitry A. Efimenko
23 Apr '13 - 8:20 
SuggestionRe: Well done!
NinjaFish
24 Apr '13 - 4:11 
GeneralRe: Well done!
Dmitry A. Efimenko
24 Apr '13 - 15:22 
AnswerRe: Well done!
NinjaFish
25 Apr '13 - 2:04 
GeneralMy vote of 5
Patrick Harris
23 Apr '13 - 3:02 
QuestionThanks for your article
Shai Aharoni
22 Apr '13 - 22:28 
GeneralMy vote of 5
AlluvialDeposit
22 Apr '13 - 20:28 
GeneralRe: My vote of 5
Dmitry A. Efimenko
22 Apr '13 - 20:41 
QuestionVery helpful, but I'm missing something
Daniel Kailer
21 Apr '13 - 20:24 
AnswerRe: Very helpful, but I'm missing something
Dmitry A. Efimenko
22 Apr '13 - 6:56 
AnswerRe: Very helpful, but I'm missing something
Dmitry A. Efimenko
22 Apr '13 - 19:06 
GeneralMy vote of 5
Monjurul Habib
11 Apr '13 - 8:18 
GeneralMy vote of 5
Prasad Khandekar
10 Apr '13 - 21:56 

Last Updated 12 May 2013 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2013