janv8000 janv8000 - 3 months ago 22
CSS Question

Checkbox inputs badly aligned when there's no accompanying label using Bootstrap and MVC5

Bootply to play with

Visual Studio 2013 generates the following CSHTML when scaffolding an edit view for a model with a boolean:

<div class="form-group">
@Html.LabelFor(model => model.IsUrgent, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.IsUrgent)
</div>
</div>
</div>


After passing through Razor you get this:

<div class="form-group">
<label class="control-label col-md-2" for="IsUrgent">Is bad :(</label>
<div class="col-md-10">
<div class="checkbox">
<input class="check-box" data-val="true" id="IsUrgent" name="IsUrgent" type="checkbox" value="true">
<input name="IsUrgent" type="hidden" value="false">
</div>
</div>
</div>


Twitter Bootstrap 3.2 however doesn't like this way of using labels because this is the result:

Screenshot

Note that the checkbox is positioned too much to the left.

If I wrap my input in a dummy label with some whitespace, ie.

<div class="form-group">
<label class="control-label col-md-2" for="IsUrgent">Is good!</label>

<div class="col-md-10">
<div class="checkbox">
<label><input class="check-box" data-val="true" id="IsUrgent" name="IsUrgent" type="checkbox" value="true">
<input name="IsUrgent" type="hidden" value="false">&nbsp;</label>
</div>
</div>
</div>


I get this:

Second screenshot

which looks nice but it's not valid HTML:


The label element may contain at most one input, button, select, textarea, or keygen descendant.


Am I doing something wrong with my CSS classes?

Edit

If I move the second
input
outside of the
label
as @Saranga suggests I'm still left with the redundant
label
that serves no semantic function ...

Answer

I implemented an Html Helper CheckBoxForBootstrap that puts the checkbox in a label but without any label text so there is no redundant label but you still get the desired formatting. The hidden field needed by mvc model binder is added after the label to it should be valid html.

public static MvcHtmlString CheckBoxForBootstrap(this HtmlHelper htmlHelper, 
        string name, 
        bool isChecked)
{

    TagBuilder checkbox = new TagBuilder("input");
    checkbox.Attributes.Add("type", "checkbox");
    checkbox.Attributes.Add("name", name);
    checkbox.Attributes.Add("id", name);
    checkbox.Attributes.Add("data-val", "true");
    checkbox.Attributes.Add("value", "true");
    if (isChecked)
        checkbox.Attributes.Add("checked", "checked");

    TagBuilder label = new TagBuilder("label");
    //nest the checkbox inside the label
    label.InnerHtml = checkbox.ToString(TagRenderMode.Normal);

    TagBuilder hidden = new TagBuilder("input");
    hidden.Attributes.Add("type", "hidden");
    hidden.Attributes.Add("name", name);
    hidden.Attributes.Add("value", "false");

    return MvcHtmlString.Create(
    label.ToString(TagRenderMode.Normal) 
    + hidden.ToString(TagRenderMode.Normal)
    );
}