Easy Bootstrap Forms in SilverStripe

Twitter Bootstrap is a great CSS framework for many reasons - responsive grid layouts, navigation styles, and form styles. However, by default, the HTML SilverStripe creates for form elements doesn't make use of the bootstrap styles.

Here's a simple way to 'bootstrap' your SilverStripe forms - using 'addExtraClass' and 'setAttribute' functions.

A Standard SilverStripe Form

A Bootstrapped SilverStripe Form

Much better!

So, let's look at our code.

public function MyForm() {
	$fields = new FieldList(
		new TextField('Name')
	);

	$actions = new FieldList(
		new FormAction('doMyForm', 'Submit')
	);

	return new Form($this, 'MyForm', $fields, $actions);
}			

Here you'll see the code the form, one text field, and one 'action' - the submit button.

To attach the bootstrap styles to the form elements, we need to apply some extra classnames

public function MyBootstrapForm() {
	$fields = new FieldList(
		$myTextField = new TextField('Name')
	);
	
	$myTextField->addExtraClass('form-group')->setAttribute('class', 'form-control');

	$actions = new FieldList(
		$mySubmit = new FormAction('doMyForm', 'Submit')
	);
	
	$mySubmit->setAttribute('class', 'btn  btn-success');

	return new Form($this, 'MyForm', $fields, $actions);
}

We've assigned out input field and our submit button to variables ($myTextField and $mySubmit) and then used two function, addExtraClass and setAttribute to attach extra class names.

addExtraClass adds a 'class' attribute, and setAttribute lets you add any attribute, in this case, we're uusing it to set a 'class'. Hmmm, so, both are setting 'class', isn't this the same? Well it should be, but due to the way the SilverStripe form templates are set up, it applies classes passed through via 'setAttribute' on a different element, which is just what we need to do get the class names attched in the way that bootsrap wants it

Other Field Types

Let's try a few other field types. Password, textarea, and dropdown (select) all work fine by adding extra classes to our SilverStripe Code:

public function MyForm2Bootsrapped() {
	$fields = new FieldList(
		$myTextField = new TextField('Name'),
		$myTextareaField = new TextareaField('Details'),
		$myPasswordField = new PasswordField('Password'),
		$myCheckboxField = new CheckboxField('agree2','I agree'),
		$myDropdownField = new DropdownField('OptionsDropdown2', 'Dropdown Options', array('NZ' => 'New Zealand','US' => 'United States', 'GEM'=> 'Germany')),
		$myOptionsetField = new OptionsetField('OptionsRadio2', 'Radio Options', array('NZ' => 'New Zealand','US' => 'United States', 'GEM'=> 'Germany'))
	);
	
	$myTextField->addExtraClass('form-group')->setAttribute('class', 'form-control');
	$myTextareaField->addExtraClass('form-group')->setAttribute('class', 'form-control');
	$myPasswordField->addExtraClass('form-group')->setAttribute('class', 'form-control');		
	$myDropdownField->addExtraClass('form-group')->setAttribute('class', 'form-control');
	
	
	$myCheckboxField->addExtraClass('form-group');	
	$myOptionsetField->addExtraClass('form-group')->setAttribute('class', 'list-unstyled');

	$actions = new FieldList(
		$mySubmit = new FormAction('doMyForm', 'Submit')
	);
	
	$mySubmit->setAttribute('class', 'btn  btn-success');

	return new Form($this, 'MyForm', $fields, $actions);
}

However....

Radio fields, and checkboxes require a little extra work. Unfortunately, the default templates for these field types simply don't have the required structure/class names required.

Luckily, they're easy to customize.

In 'mysite/templates/forms/' create these 2 files:

1: CheckboxField_holder.ss


<div id="$HolderID" class="field<% if extraClass %> $extraClass<% end_if %>">
	
	<label class="right" for="11">
		$Field
		$Title	
	</label>
	
	<% if $Message %><span class="message $MessageType">$Message</span><% end_if %>
	<% if $Description %><span class="description">$Description</span><% end_if %>
</div>

		

2: OptionsetField.ss

<div $AttributesHTML>
	<% loop $Options %>
		<div class="$Class radio">
			
			<label for="$ID">
				<input id="$ID" class="radio" name="$Name" type="radio" value=""<% if $isChecked %> checked<% end_if %><% if  %> disabled<% end_if %> />
				$Title
			</label>
		</div>
	<% end_loop %>
</div>

		

Go back to your page, don't forget to '?flush=all' so SilverStripe can find these new template files, and you should see a perfect Bootstrap style form