Documentation
1.1-P24-B3  Play 2.4  Bootstrap 3 

This page explains each component in more details.

Field Constructors

There are 4 different field constructors you can use. You only need to declare any of them implicitly on top of your template. Then every input will take it by default. All of them extend the b3.B3FieldConstructor class.

Vertical forms

@implicitFieldConstructor = @{ b3.vertical.fieldConstructor }

Or simply:

@import b3.vertical.fieldConstructor

This will let you render form-group's like this:

<div class="form-group" id="foo_field">
  <label class="control-label" for="foo">A simple text</label>
  <input type="text" id="foo" name="foo" value="" aria-describedby="foo_info_0" class="form-control" placeholder="A simple text showing a help...">
  <span id="foo_info_0" class="help-block">This is a help text</span>
</div>

Horizontal forms

You have to specify its column widths for the form-group.

@implicitFieldConstructor = @{ b3.horizontal.fieldConstructor("col-md-2", "col-md-10") }

This will let you render form-group's like this:

<div class="form-group" id="foo_field">
  <label class="control-label col-md-2" for="foo">A simple text</label>
  <div class="col-md-10">
    <input type="text" id="foo" name="foo" value="" aria-describedby="foo_info_0" class="form-control" placeholder="A simple text showing a help...">
    <span id="foo_info_0" class="help-block">This is a help text</span>
  </div>
</div>

Inline forms

@implicitFieldConstructor = @{ b3.inline.fieldConstructor }

Or:

@import b3.inline.fieldConstructor

This will let you render form-group's like this:

<div class="form-group" id="foo_field">
  <label class="control-label sr-only" for="foo">A simple text</label>
  <input type="text" id="foo" name="foo" value="" aria-describedby="foo_info_0" class="form-control" placeholder="A simple text showing a help...">
  <span id="foo_info_0" class="help-block">This is a help text</span>
</div>

Clear field constructor

This field constructor renders the input helpers directly. It is useful for those cases you need the input without its corresponding form-group. However, although it is used for specific cases, you can also declare it as the default field constructor within a template.

@import b3.clear.fieldConstructor

Specific field constructors

There are also 4 extra field constructors reserved to use for specify them instead of the default one. In short, these field constructors are equivalent to the previous ones but they are preferred when an implicit field constructor is needed. See the section Forms with a specific B3FieldConstructor for more details.

b3.vertical.fieldConstructorSpecific
b3.horizontal.fieldConstructorSpecific("col-md-2", "col-md-10")
b3.inline.fieldConstructorSpecific
b3.clear.fieldConstructorSpecific

Arguments (args)

For every component there is a list of arguments you can add and they will be put within the corresponding input tag as normal HTML. However it will only happen with those arguments without a prefixed underscore (_). The underscored arguments are used to complement the corresponding form-group or to parameterize its behaviour.

For example, the following component has the argument placeholder that will be added to the input text tag. The _label argument set the label for the form-group and the _showConstraints one specifies if the constraints should be shown.

Maximum length: 10
@b3.text( fooForm("foo"), '_label -> "Constraints", '_showConstraints -> true, 'placeholder -> "A simple text showing its constraints..." )

The previous example outputs the HTML:

<div class="form-group" id="foo_field">
  <label class="control-label" for="foo">Constraints</label>
  <input type="text" id="foo" name="foo" value="" class="form-control" placeholder="A simple text showing its constraints...">
  <span class="help-block">Maximum length: 10</span>
</div>

Special arguments (the underscored ones)

As we see before, there are some special arguments that are reserved to parameterize the corresponding form-group's behaviour. All of these special arguments are prefixed with an underscore (_). And the list is:

  • _id: the id for the form-group. If it isn't present, the default value will be the input's id with the suffix "_field".
  • _class: the class for the form-group (the form-group class is always added).
  • _label: the text for the label. It's automatically internationalized.
  • _hideLabel: a boolean indicating if the label must be hidden. It will be rendered into the DOM, but it will add the class sr-only to the label to hide it.
  • _hiddenLabel: a shortcut to use a hidden label instead of using _label and _hideLabel. It's automatically internationalized.
  • _showConstraints: indicates if the constraints are shown.
  • _help: a help text below the input. It's automatically internationalized.
  • _success: could be:
    • Boolean: indicates if the field should show an success validation status.
    • Any: calls toString method to show a internationalized help text.
  • _warning: could be:
    • Boolean: indicates if the field should show an warning validation status.
    • Any: calls toString method to show a internationalized help text.
  • _error: could be:
    • Boolean: indicates if the field should show an error validation status.
    • Option[play.api.data.FormError]: shows the corresponding error as a help text if it's defined.
    • Any: calls toString method to show a internationalized help text.
  • _showErrors: boolean indicating if the errors should be shown. True is the default value.
  • _showIconOnError: a boolean indicating if an error icon should be shown if there is any error.
  • _showIconWarning: a boolean indicating if a warning icon should be shown if there is no error.
  • _showIconValid: a boolean indicating if a success icon should be shown if there is no error.
About the labels

Note there are 3 arguments for rendering the label for each field: '_label, '_hideLabel and '_hiddenLabel. Screen readers will have trouble with your forms if you don't include a label for every input. So you should always add a label even if you don't want it to be displayed. That's the reason for hiding the label. Let's see when to use each case with some examples:

  • '_label: the general case.
    @b3.text( fooForm("foo"), '_label -> "Input Text", 'placeholder -> "A simple text..." )
  • '_hiddenLabel (or '_label with '_hideLabel): for that cases you don't want the label to be displayed. For example when you use inline forms.
    @import b3.inline.fieldConstructor
    @b3.text( fooForm("foo"), '_hiddenLabel -> "Input Text", 'placeholder -> "A simple text..." )
  • Nothing: simply omit any of these arguments for that cases you don't want to render the label even into the DOM. Use this case only if you have a reason for that. For example, you should not add any label when you don't want to display it for checkboxes or radio buttons, because they use their own inner labels for each option.
    // checkbox and radio without label
    @b3.checkbox( fooForm("foo"), '_text -> "Checkbox", 'checked -> true )
    @b3.radio( fooForm("foo"), options = Seq("M"->"Male","F"->"Female") )

Validation arguments

If a field has validation constraints they will be added automatically as HTML5 data form validation (please visit this web to learn more and check wufoo for more examples and browser compatibility).

Then, the following constraints are automatically represented in HTML with these corresponding attributes:

  • nonEmpty and nonEmptyTextrequired="true"
  • minLengthminlength="N"
  • maxLengthmaxlength="N"
  • minmin="N"
  • maxmax="N"
  • patternpattern="XXX"

Remember you have also the specific b3.email, b3.url and b3.number helpers for the corresponding validations.

For example, if you have this form

val validationForm = Form(tuple(
  "username" -> nonEmptyText(maxLength = 20),
  "email" -> email,
  "age" -> number(min = 18, max = 99),
  "color" -> nonEmptyText.verifying(pattern("^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$".r))
))

and this CSS

input:valid { color: green; }
input:invalid { color: red; }

The constraints will be automatically added as you can see here:

A username between 1 and 20 characters
From 18 to 99 years old
Format is #CCC or #CCCCCC
@b3.text( validationForm("username"), '_label -> "Username", '_help -> "A username between 1 and 20 characters" )
@b3.email( validationForm("email"), '_label -> "Email" )
@b3.number( validationForm("age"), '_label -> "Age", '_help -> "From 18 to 99 years old" )
@b3.text( validationForm("color"), '_label -> "Hexadecimal color", '_help -> "Format is #CCC or #CCCCCC" )

Optional arguments

In some cases, you may need to add an argument only if a condition happens. In this situation you can simply use an Option value and it will be omitted if it is not defined (i.e. None).

'foo -> Some("foo-value")   // foo="foo-value"
'foo -> None                // (this argument is omitted)
'foo -> maybeValue(...)     // foo="result-value"  or  it's ommited

Boolean arguments

The boolean arguments are simply that, booleans. Let's see an example for the disabled attribute. Look all of these different codes:

<input type="text" name="foo" disabled>
<input type="text" name="foo" disabled="true">
<input type="text" name="foo" disabled="false">
<input type="text" name="foo" disabled="blah">

And all of them are equivalents... But don't worry, every false argument will be automatically removed. So you can feel free to do something like:

@b3.text( fooForm("foo"), '_label -> "A maybe disabled text", 'disabled -> maybeTrueFunction(...) )

And what happens if you need to set a "false" value to an attribute? Ok, you can simply convert it to a string:

@b3.text( fooForm("foo"), '_label -> "With a false attribute", 'fooAttr -> "false" )
@b3.text( fooForm("foo"), '_label -> "With a boolean attribute", 'fooAttr -> maybeTrueFunction(...).toString )

Note only regular arguments with false value are removed. It doesn't happen with the special ones (i.e. the underscored ones).

Arguments with dashes (e.g. data-* attributes)

You always add any argument to helpers using tuples of (Symbol, Any), like 'class -> "foo-class". However, when you need to add an argument with dashes you cannot declare the symbol as 'data-attr. So to get this you have different solutions:

  • Create the Symbol directly with its apply method: Symbol("data-attr") -> "data-value".
  • Import the implicit views.html.helper.Implicits.toAttributePair with simply @import helper.Implicits._. And then you will be able to declare the argument as "data-attr" -> "data-value".

ARIA attributes

The WAI-ARIA attributes are a very helpful tool for accesibility. However we know it could be difficult and boring to integrate it everywhere within your web. Because of that, the library will do automatically for you for any field constructor.

@b3.text( fooForm("text"), '_label -> "A text", '_help -> "Something helpful" )

And it will render the following if there is an error:

<div class="form-group has-error has-feedback" id="text_field">
  <label class="control-label" for="text">A text</label>
  <input type="text" id="text" name="text" value="" aria-describedby="text_info_0 text_error_0" aria-invalid="true" class="form-control">
  <span id="text_error_0" class="help-block">This field is required</span>
  <span id="text_info_0" class="help-block">Something helpful</span>
</div>

Note the library adds automatically for you:

  • A span for each error with an autogenerated id attribute.
  • A span for each extra information (i.e. a help block added with a '_help argument or any constraint if '_showConstraints is active) with an autogenerated id attribute.
  • The aria-describedby attribute for the input with the list of every span it has added.
  • If there is any error, it is also added he aria-invalid attribute for the input setted to true.

Forms @(action: Call, args: (Symbol, Any)*)(body: => Html)(implicit fc: B3FieldConstructor)

The b3.form takes a Call object and a list of arguments. The implicit B3FieldConstructor argument is used to know which class is needed. Each B3FieldConstructor add its corresponding class:

  • HorizontalFieldConstructor: class="form-horizontal"
  • InlineFieldConstructor: class="form-inline"
  • VerticalFieldConstructor: class="form-vertical"
  • ClearFieldConstructor: class="form-clear"
The last two ones don't belong to Bootstrap 3, but they could be useful for your own CSS. Every other class you include within args will be appended to this required one.

The helper also adds the role="form" attribute by default.

Forms with a specific B3FieldConstructor

Every input helper will use the default B3FieldConstructor (the implicit one), unless you specify another. To do this you can use the form helper. There is one for each type of form. Here is an example of how to add an inline form within a view with a vertical form as default.

@import b3.vertical.fieldConstructor
@b3.form(routes.Application.handleRequest) { // vertical form as default
  @b3.text( fooForm("foo"), '_label -> "Input Text" )
  ...
}
@b3.inline.form(routes.Application.handleRequest) { implicit ifc => // an inline form
  @b3.text( fooForm("foo"), '_label -> "Input Text" )
  ...
}

There are 4 different options to insert each type of form. Note that there is also one for a clear B3FieldConstructor (it simply outputs the input helper without any more). So we have:

@b3.vertical.form(routes.Application.handleRequest) { implicit vfc => ... }
@b3.horizontal.form(routes.Application.handleRequest, "col-md-2", "col-md-10") { implicit hfc => ... }
@b3.inline.form(routes.Application.handleRequest) { implicit ifc => ... }
@b3.clear.form(routes.Application.handleRequest) { implicit cfc => ... }

If you would need to specify a different B3FieldConstructor within a form, you can do:

@import b3.vertical.fieldConstructor
@horizontalFC = @{ b3.horizontal.fieldConstructor("col-md-2", "col-md-10") }
@b3.form(routes.Application.handleRequest) { // vertical form as default
  @b3.text( fooForm("foo"), '_label -> "Vertical input text" )
  @b3.text( fooForm("bar"), '_label -> "Horizontal input text" )(horizontalFC, implicitly[Messages])
  ...
}

Or:

@import b3.vertical.fieldConstructor
@b3.form(routes.Application.handleRequest) { // vertical form as default
  @b3.text( fooForm("foo"), '_label -> "Vertical input text" )
  ...
  // an inline inner section
  @defining(b3.inline.fieldConstructorSpecific) { implicit ifc =>
    @b3.text( fooForm("bar"), '_label -> "Inline input text" )
    ...
  }
  ...
}

But remember that horizontal and inline controls need to be inside their corresponding .form-horizontal and .form-inline to be rendered correctly. So you may need to wrap them with a div with these classes.

Forms with CSRF token

If you want to add automatically a CSRF token to a form, you can do it simply using the equivalent formCSRF. Be sure you implement your project correctly for CSRF support as it is explained at the Play's documentation.

@b3.formCSRF(...) { ... }
@b3.vertical.formCSRF(...) { implicit vfc => ... }
@b3.horizontal.formCSRF(...) { implicit hfc => ... }
@b3.inline.formCSRF(...) { implicit ifc => ... }
@b3.clear.formCSRF(...) { implicit cfc => ... }

It will simply add the helper @helper.CSRF.formField(token) within the form for you.

Input helpers

About disabled and readonly attributes

Both the disabled and readonly attributes for an input prevent the user from modify it. However, the disabled attribute means this input will NOT be sent within the POST request, whereas the readonly one means it will.

Nevertheless, for checkbox, radio and select tags it doesn't happen. To support the readonly attribute for these tags, the corresponding helpers have been adapted to behave as would be expected. To do that, when the readonly attribute appears the helper will:

  • add an additional disabled attribute
  • add an additional <input type="hidden"> with the desired value
  • wraps them with in a div (with class checkbox-group, radio-group or select-group)
Note it only happens when the readonly attribute is present, even with a false value. It is done to make it easier to modify its readonly behaviour using javascript.

You can see an example in the Readonly Demo.

Validation states & feedback icons

You can set any validation state for a field with one of the following special arguments:

  • _success: could be:
    • Boolean: indicates if the field should show an success validation status.
    • Any: calls toString method to show a internationalized help text.
  • _warning: could be:
    • Boolean: indicates if the field should show an warning validation status.
    • Any: calls toString method to show a internationalized help text.
  • _error: could be:
    • Boolean: indicates if the field should show an error validation status.
    • Option[play.api.data.FormError]: shows the corresponding error as a help text if it's defined.
    • Any: calls toString method to show a internationalized help text.
Be carefull with this...
An error occurred!
@b3.text( fooForm("foo"), '_label -> "Success", '_success -> true, 'placeholder -> "Success text..." )
@b3.text( fooForm("foo"), '_label -> "Warning", '_warning -> "Be carefull with this...", 'placeholder -> "Warning text..." )
@b3.text( fooForm("foo"), '_label -> "Error", '_error -> "An error occurred!", 'placeholder -> "Error text..." )

You can also add optional feedback icons with the addition of:

  • _showIconValid: a boolean indicating if a success icon should be shown if there is no error.
  • _showIconWarning: a boolean indicating if a warning icon should be shown if there is no error.
  • _showIconOnError: a boolean indicating if an error icon should be shown if there is any error.
(success)
(warning) Be carefull with this...
(error) An error occurred!
@b3.text( fooForm("foo"), '_label -> "Success", '_showIconValid -> true, 'placeholder -> "Success text..." )
@b3.text( fooForm("foo"), '_label -> "Warning", '_warning -> "Be carefull with this...", '_showIconWarning -> true, 'placeholder -> "Warning text..." )
@b3.text( fooForm("foo"), '_label -> "Error", '_showIconOnError -> true, '_error -> "An error occurred!", 'placeholder -> "Error text..." )

b3.inputType @(inputType: String, field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It renders a simple input with a specific type attribute and it adds class="form-control" by default, but you can add an extra class with 'class -> "extra_class".

The argument 'placeholder is automatically internationalized.

With at least 8 characters
@b3.inputType( "text", fooForm("name"), 'class -> "extra_class", '_label -> "Name", 'placeholder -> "John Doe" )
@b3.inputType( "email", fooForm("email"), '_label -> "Email", 'placeholder -> "example@mail.com" )
@b3.inputType( "password", fooForm("password"), '_label -> "Password", '_help -> "With at least 8 characters" )

b3.text @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="text".

@b3.text( fooForm("name"), '_label -> "Name", 'placeholder -> "John Doe" )

b3.password @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="password".

For security reasons, this helper doesn't display the possible value the field could have (for example when the form is reloaded after a validation failure).

With at least 8 characters
@b3.password( fooForm("password"), '_label -> "Password", '_help -> "With at least 8 characters" )

b3.file @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="file".

@b3.file( fooForm("file"), '_label -> "File" )
@b3.file( fooForm("file"), '_label -> "File", 'class -> "form-control" )

b3.textarea @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It renders a textarea and it adds class="form-control" by default.

@b3.textarea( fooForm("foo"), '_label -> "Textarea", 'rows -> 3 )

b3.checkbox @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It renders a checkbox. It has the attribute value set to true by default, but you can use another one using the 'value argument.

The special '_text argument lets you put a text after the checkbox. It is automatically internationalized.

Regarding to the checked attribute, if you want to set it to true as default, use '_default -> true. And if you need to force its value use directly the 'checked argument.

It supports readonly attribute adding an additional disabled one and a <input type="hidden">.

@b3.checkbox( fooForm("foo"), '_text -> "Remember me" )
// uses "bar" as value for the checkbox
@b3.checkbox( fooForm("foo"), '_text -> "Remember me", 'value -> "bar" )
// checked by default (if the form is filled, this value will be taken)
@b3.checkbox( fooForm("foo"), '_text -> "Remember me", '_default -> true )
        
// always checked (even if the form has been filled with a false)
@b3.checkbox( fooForm("foo"), '_text -> "Remember me", 'checked -> true )
// disabled -> it will NOT be sent within the POST request
@b3.checkbox( fooForm("foo"), '_text -> "Remember me", 'disabled -> true )
// readonly -> it will be sent within the POST request
@b3.checkbox( fooForm("foo"), '_text -> "Remember me", 'readonly -> true )

Note you can use any value for the _text argument.

@b3.checkbox( fooForm("foo"), '_text -> Html("Do you want a beer? <i class=\"fa fa-beer\"></i>") )

b3.radio @(field: Field, options: Seq[(String, Any)], args: (Symbol, Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It renders a radio. It supports readonly attribute adding an additional disabled one and a <input type="hidden">.

It has an additional special _inline argument to make it an inline radio (for vertical and horizontal forms).

@opts = @{ Seq("M"->"Male","F"->"Female") }
@b3.radio( fooForm("foo"), options = opts, '_label -> "Radio Group" )
// an inline radio within a vertical or horizontal form
@b3.radio( fooForm("foo"), options = opts, '_label -> "Radio Group", '_inline -> true )
// with value "F" by default (if the form is filled, this value will be taken)
@b3.radio( fooForm("foo"), options = opts, '_label -> "Radio Group", 'value -> "F" )
// disabled -> it will NOT be sent within the POST request
@b3.radio( fooForm("foo"), options = opts, '_label -> "Radio Group", 'disabled -> true )
// readonly -> it will be sent within the POST request
@b3.radio( fooForm("foo"), options = opts, '_label -> "Radio Group", 'readonly -> true )

Note you can use any value for the options argument. But they are automatically internationalized only for _String_ values.

@b3.radio( fooForm("foo"), options = Seq("B" -> Html("Beer <i class=\"fa fa-beer\"></i>"), "C" -> Html("Coffee <i class=\"fa fa-coffee\"></i>")), '_label -> "What do you prefer?" )
b3.radio @(field: Field, args: (Symbol, Any)*)(content: Tuple6[Boolean, Boolean, String, String, Option[String], Map[Symbol, Any]] => Html)(implicit handler: B3FieldConstructor, messages: Messages)
b3.radioOption @(inputValue: Any, text: Any, args: (Symbol, Any)*)(implicit extraInfo: (Boolean, Boolean, String, String, Option[String], Map[Symbol,Any]), messages: Messages)

If you need more versatility you can fully customize your radio options:

@b3.radio( fooForm("foo3"), '_label -> "Ok, now that we're alone, what do you really prefer?" ) { implicit extraInfo =>
  @b3.radioOption("B", Html("Beer <i class=\"fa fa-beer\"></i>"))
  @b3.radioOption("B", Html("Coffee <i class=\"fa fa-coffee\"></i>"), 'disabled -> true)
}

Note you can use any value for the text argument. But it is automatically internationalized only for _String_ values.

b3.select @(field: Field, options: Seq[(String,String)], args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It renders a select. It supports readonly attribute adding an additional disabled one and a <input type="hidden">.

Note the value for each option argument is automatically internationalized.

@fruits = @{ Seq("A"->"Apples","P"->"Pears","B"->"Bananas") }
@b3.select( fooForm("foo"), options = fruits, '_label -> "Select" )
// disabled -> it will NOT be sent within the POST request
@b3.select( fooForm("foo"), options = fruits, '_label -> "Select", 'disabled -> true )
// readonly -> it will be sent within the POST request
@b3.select( fooForm("foo"), options = fruits, '_label -> "Select", 'readonly -> true )

You can add a default first value using the argument '_default with a string. It will add a first option to the select with an empty string value. So you could add a required constraint to the field to force the user to select one other option. In addition, this default option is always disable to avoid the user to select it, and if any other option is selected this default one will not appear at all. Note it's automatically internationalized.

@b3.select( fooForm("foo"), options = fruits, '_label -> "Select", '_default -> "Select an option" )
@b3.select( fooForm("foo"), options = fruits, '_label -> "With default and Pears as value", '_default -> "Select an option", 'value -> "P" )

For a multiple select you only need to add the 'multiple argument. In that case, the '_default argument will be ignored.

@fruits = @{ Seq("A"->"Apples","P"->"Pears","B"->"Bananas") }
@b3.select( fooForm("foo"), options = fruits, '_label -> "Fruits", 'multiple -> true )
// with value "A" and "B" by default
// it is a string with every value separated by commas
@b3.select( fooForm("foo"), options = fruits, '_label -> "Fruits", 'multiple -> true, 'value -> "A,B" )
b3.select @(field: Field, args: (Symbol,Any)*)(content: Set[String] => Html)(implicit handler: B3FieldConstructor, messages: Messages)
b3.selectOption @(value: Any, name: Any, args: (Symbol, Any)*)(implicit values: Set[String], messages: Messages)

If you need more versatility you can fully customize your select options:

@b3.select( fooForm("foo"), '_label -> "Grouped select" ) { implicit values =>
  <optgroup label="Group 1">
    @b3.selectOption("opt_1-1", "Option 1.1")
    @b3.selectOption("opt_1-2", "Option 1.2", 'disabled -> true)
    @b3.selectOption("opt_1-3", "Option 1.3")
  </optgroup>
  <optgroup label="Group 2">
    @b3.selectOption("opt_2-1", "Option 2.1", 'disabled -> true)
    @b3.selectOption("opt_2-2", "Option 2.2")
  </optgroup>
}
class Fruit (id: Long, name: String, isCitrus: Boolean)
@fruitsWithCitrus = @{ Seq(
  Fruit(1L, "Apple", false),
  Fruit(2L, "Orange", true),
  Fruit(3L, "Pear", false),
  Fruit(4L, "Lemon", true),
  Fruit(5L, "Banana", false)
)}
@b3.select( fooForm("foo"), '_label -> "Fruits select (lemon preselected)" ) { implicit values =>
  <optgroup label="Citrus fruits">
    @fruitsWithCitrus.filter(_.isCitrus).map { citrus =>
      @b3.selectOption(citrus.id, citrus.name, 'selected -> (citrus.name == "Lemon"))
    }
  </optgroup>
  <optgroup label="Rest of fruits">
    @fruitsWithCitrus.filterNot(_.isCitrus).map { fruit =>
      @b3.selectOption(fruit.id, fruit.name)
    }
  </optgroup>
}

Note the value for the name is automatically internationalized.

b3.hidden @(name: Any, value: Any, args: (Symbol, Any)*)

It simply renders a hidden input.

@b3.hidden("fooName", "fooValue", 'fooAttr -> "fooAttrValue")

Renders to:

<input type="hidden" name="fooName" value="fooValue" fooAttr="fooAttrValue">

b3.hiddens @(namesAndValues: (Any, Any)*)

Render a list of hidden inputs.

@b3.hiddens("fooId" -> 1L, "barId" -> 2L)

Renders to:

<input type="hidden" name="fooId" value="1">
<input type="hidden" name="barId" value="2">

New HTML5 helpers

Important note: the new HTML5 input types are not fully supported for web browsers. Those not supported by old web browsers, will behave as input type text.

b3.color @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="color".

@b3.color( fooForm("color"), '_label -> "Color", 'value -> "#3264c8" )

b3.date @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="date".

@b3.date( fooForm("date"), '_label -> "Date" )

b3.datetime @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="datetime".

@b3.datetime( fooForm("datetime"), '_label -> "Datetime" )

b3.datetimeLocal @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="datetime-local".

@b3.datetimeLocal( fooForm("datetimeLocal"), '_label -> "Datetime-Local" )

b3.email @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="email".

@b3.email( fooForm("email"), '_label -> "Email", 'placeholder -> "example@mail.com" )

b3.month @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="month".

@b3.month( fooForm("month"), '_label -> "Month" )

b3.number @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="number".

@b3.number( fooForm("number"), '_label -> "Number", 'min -> 0, 'max -> 50, 'step -> 5 )

b3.range @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="range".

@b3.range( fooForm("range"), '_label -> "Range", 'min -> 0, 'max -> 50 )

It is a short version of b3.inputType for type="search".

@b3.search( fooForm("search"), '_label -> "Search" )

b3.tel @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="tel".

@b3.tel( fooForm("tel"), '_label -> "Telephone" )

b3.time @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="time".

@b3.time( fooForm("time"), '_label -> "Time" )

b3.url @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="url".

@b3.url( fooForm("url"), '_label -> "URL" )

b3.week @(field: Field, args: (Symbol,Any)*)(implicit handler: B3FieldConstructor, messages: Messages)

It is a short version of b3.inputType for type="week".

@b3.week( fooForm("week"), '_label -> "Week" )

More helpers

The following helpers use an auxiliar helper that creates a form-group without a field. Here are the special arguments they use:

  • _id: the id for the form-group.
  • _class: the class for the form-group (the form-group class is always added).
  • _label: the text for the label.
  • _help: a help text below the input.

b3.static @(label: String, args: (Symbol,Any)*)(text: => Html)(implicit fc: B3FieldConstructor, messages: Messages)

It renders a static control to place within your form. It takes a HTML as parameter, so you can render whatever you want. Actually, it is like a wrapper for a static HTML.

This is a link

@b3.static("Static HTML"){ <a href="#"><span class="glyphicon glyphicon-star"></span> This is a link</a> }

There are two equivalent more versions of b3.static helper: one for labels with HTML, and another one to omit the label. Note that you can also have a hidden label using '_hideLabel' argument.

@b3.static(Html("Label with icon <i class=\"fa fa-beer\"></i>")){ <a href="#">Basic control with label</a> }
@b3.static("Hidden label", '_hideLabel -> true){ <a href="#">Basic control with hidden label</a> }
@b3.static(){ <a href="#">Basic control without label</a> }

b3.buttonType @(buttonType: String, args: (Symbol,Any)*)(text: => Html)(implicit fc: b3.B3FieldConstructor, messages: Messages)

It renders a simple button to place within your form. It takes a HTML as parameter, so you can render whatever you want.

@b3.buttonType("submit", 'class -> "btn btn-default"){ <span class="glyphicon glyphicon-ok"></span> Sign in }

b3.submit @(args: (Symbol,Any)*)(text: => Html)(implicit fc: B3FieldConstructor, messages: Messages)

It is a short version of b3.buttonType for type="submit".

@b3.submit('class -> "btn btn-primary"){ <span class="glyphicon glyphicon-ok"></span> Sign in }

b3.reset @(args: (Symbol,Any)*)(text: => Html)(implicit fc: B3FieldConstructor, messages: Messages)

It is a short version of b3.buttonType for type="reset".

@b3.reset('class -> "btn btn-danger"){ <span class="glyphicon glyphicon-remove"></span> Reset }

b3.button @(args: (Symbol,Any)*)(text: => Html)(implicit fc: B3FieldConstructor, messages: Messages)

It is a short version of b3.buttonType for type="button".

@b3.button('class -> "btn btn-default"){ <span class="glyphicon glyphicon-heart"></span> Favorite }

b3.free @(args: (Symbol,Any)*)(content: => Html)(implicit fc: B3FieldConstructor, messages: Messages)

It renders whatever you want within a form-group div.

Cancel
@b3.free('_id -> "idFormGroup") {
  <button type="submit" class="btn btn-primary"> <span class="glyphicon glyphicon-ok"></span> Save changes</button>
  <a class="btn btn-default"> <span class="glyphicon glyphicon-remove"></span> Cancel</a>
}

Your own custom helpers

The purpose of these helpers is to be a tool for creating your own helpers. Please see more about creating new helpers here.

b3.inputWrapped @(inputType: String, field: Field, args: (Symbol,Any)*)(inputGroup: Html => Html)(implicit handler: B3FieldConstructor, messages: Messages)

This is the same as b3.inputType but specifying a custom wrapper for the input tag. It is useful for input groups and inputs with validation states and feedback icons.

@b3.inputWrapped( "email", fooForm("email"), '_label -> "Email", 'placeholder -> "example@mail.com" ) { input =>
  <div class="input-group">
    <span class="input-group-addon">@@</span>
    @input
    <div class="input-group-btn">
      <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Action <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
  </div>
}

b3.multifield @(fields: Field*)(args: (Symbol,Any)*)(inputsHtml: (B3FieldConstructor, Messages) => Html)(implicit fc: B3FieldConstructor, messages: Messages)

Sometimes you may need two or more fields within the same line in a horizontal or vertical form (for a set of checkboxes, a date range, ...).

The helper b3.multifield tries to:

  • Manage a set of fields and group them within the same form-group.
  • Manage all of their errors, infos and constraints at the end of the form-group as if they were only one.
  • Take advantage of the helpers that are already implemented.
  • Be a tool to create your custom multifield helpers.

To know how it works and how to use it go the the Multifield section.