Development | 02.17.2014
Multi-Column Gravity Forms With CSS
Update 7/1/2016
For a better solution, check out our more recent article about multi-column Gravity Forms implementation: Revisited: Multi-Column Gravity Forms
There is no built-in way for the Gravity Forms plugin for WordPress to generate a true, multi-column form layout. However, this can easily be accomplished using a single filter hook and some accompanying CSS.
Occasionally, the mockups I’m using to build a WordPress site call for a multi-column form. Natively, Gravity Forms doesn’t support something likes this. Sure, they have what they call “CSS ready classes” for fields that will arrange form inputs in multiple columns when they’re ordered one right after the other. But what if the fields I want to appear side by side shouldn’t contextually be one right after the other?
From a user experience standpoint, it might make more sense to complete a form’s left column of fields before continuing on to the right column. You may be able to get away with using Gravity Form’s CSS ready classes to arrange them how you want but you wouldn’t be considering situations when the form has to go to a single column layout, such as for mobile devices. It’d really make more sense to group what you want to go in each column together so you may lay out each group side by side.
What We’re Working With
When looking at the HTML output by Gravity Forms, you’ll notice that all fields are organized into an unordered list with the class of .gform_fields
:
<ul id="gform_fields_1" class="gform_fields top_label description_below">
<li id="field_1_1" class="gfield"><label class="gfield_label" for="input_1_1">Field 1</label>
<div class="ginput_container"><input id="input_1_1" class="medium" tabindex="1" name="input_1" type="text" value="" /></div></li>
<li id="field_1_2" class="gfield"><label class="gfield_label" for="input_1_2">Field 2</label>
<div class="ginput_container"><input id="input_1_2" class="medium" tabindex="2" name="input_2" type="text" value="" /></div></li>
<li id="field_1_3" class="gfield"><label class="gfield_label" for="input_1_3">Field 3</label>
<div class="ginput_container"><textarea id="input_1_3" class="textarea medium" tabindex="3" cols="50" name="input_6" rows="10"></textarea></div></li>
</ul>
The most logical way of splitting the third field off from the first two would be to separate it into its own list. If we can get the form’s fields to be organized into two separate lists, we could specify them to float left to get a two column layout while still being able to easily revert to a stacked layout for narrower devices.
Splitting the Columns
In order to split the fields list, first we’ll need to designate where we want these splits to occur. This can be achieved by adding special section break elements to our form using the form editor. We can mark these as column breaks by adding a special class to these section breaks, such as .gform_column
. For example, for a two column layout, we’d have a section break as the first form field and another section break wherever we need the right column’s field to start. It’s also a good idea to specify the type of layout the form will take on by providing a class to the form itself, such as .two-column
. Not only will we use these classes for styling the columns via CSS, we will use these classes to selectively target the correct column break points when generating the form’s HTML.
Using Gravity Forms’ gform_field_content
filter hook, we can add the breaks to the unordered list to designate column breaks:
function gform_column_splits($content, $field, $value, $lead_id, $form_id) {
if(IS_ADMIN) return $content; // only modify HTML on the front end
$form = RGFormsModel::get_form_meta($form_id, true);
$form_class = array_key_exists('cssClass', $form) ? $form['cssClass'] : '';
$form_classes = preg_split('/[nrt ]+/', $form_class, -1, PREG_SPLIT_NO_EMPTY);
$fields_class = array_key_exists('cssClass', $field) ? $field['cssClass'] : '';
$field_classes = preg_split('/[nrt ]+/', $fields_class, -1, PREG_SPLIT_NO_EMPTY);
// multi-column form functionality
if($field['type'] == 'section') {
// check for the presence of multi-column form classes
$form_class_matches = array_intersect($form_classes, array('two-column', 'three-column'));
// check for the presence of section break column classes
$field_class_matches = array_intersect($field_classes, array('gform_column'));
// if field is a column break in a multi-column form, perform the list split
if(!empty($form_class_matches) && !empty($field_class_matches)) { // make sure to target only multi-column forms
// retrieve the form's field list classes for consistency
$ul_classes = GFCommon::get_ul_classes($form).' '.$field['cssClass'];
// close current field's li and ul and begin a new list with the same form field list classes
return '
<ul class="'.$ul_classes.'">
<li class="gfield gsection empty">';}
}return $content;
}
add_filter('gform_field_content', 'gform_column_splits', 10, 5);
Note how we’ve added the field’s CSS class to the new <ul>
. This will allow us to target that list for applying a CSS float.
After this filter is applied, we should end up with something like this:
<ul id="gform_fields_1" class="gform_fields top_label description_below">
<li id="field_1_1" class="gfield gsection gform_column"></li>
</ul>
<ul class="gform_fields top_label description_below gform_column">
<li class="gfield gsection"></li>
<li id="field_1_2" class="gfield"><label class="gfield_label" for="input_1_2">Field 1</label>
<div class="ginput_container"><input id="input_1_2" class="medium" tabindex="1" name="input_2" type="text" value="" /></div></li>
<li id="field_1_3" class="gfield"><label class="gfield_label" for="input_1_3">Field 2</label>
<div class="ginput_container"><input id="input_1_3" class="medium" tabindex="2" name="input_3" type="text" value="" /></div></li>
<li id="field_1_4" class="gfield gsection gform_column"></li>
</ul>
<ul class="gform_fields top_label description_below gform_column">
<li class="gfield gsection"></li>
<li id="field_1_5" class="gfield"><label class="gfield_label" for="input_1_5">Field 3</label>
<div class="ginput_container"><textarea id="input_1_5" class="textarea medium" tabindex="3" cols="50" name="input_5" rows="10"></textarea></div></li>
</ul>
We’ve successfully split the third field into it’s own list!
Column Styling
Now that we have the fields we want grouped together in separate lists, we can style the form so both of these groups appear side by side. The actual CSS will vary from project to project, depending on the site’s design, but this would be one way of accomplishing the two-column layout:
.gform_wrapper.two-column_wrapper ul.gform_fields {
display: none;
}
.gform_wrapper.two-column_wrapper ul.gform_fields.gform_column {
display: block;
float: left;
width: 50%;
}
.gform_wrapper.two-column_wrapper ul.gform_column li.gsection:first-child {
display: none;
}
The first style definition hides the unecessary field list at the beginning of the form by hiding all .gform_fields
lists. The next definition overrides the previous just for .gform_column
lists. The final style definition hides the empty <li>
elements at the beginning of each column list.
We now have a multi-column form that can easily be restructured into a single column while keeping each column’s fields grouped together!