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?

Contextually, the third field should really come after the second in the HTML structure.

Contextually, the third field should really come after the second in the HTML structure.

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:

html
<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 name="input_1" id="input_1_1" type="text" value="" class="medium" tabindex="1">
		</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 name="input_2" id="input_1_2" type="text" value="" class="medium" tabindex="2">
		</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 name="input_6" id="input_1_3" class="textarea medium" tabindex="3" rows="10" cols="50"></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:

php
function gform_column_splits($content, $field, $value, $lead_id, $form_id) {
	if(!IS_ADMIN) { // only perform on the front end

		// target section breaks
		if($field['type'] == 'section') {
			$form = RGFormsModel::get_form_meta($form_id, true);

			// check for the presence of our special multi-column form class
			$form_class = explode(' ', $form['cssClass']);
			$form_class_matches = array_intersect($form_class, array('two-column'));

			// check for the presence of our special section break column class
			$field_class = explode(' ', $field['cssClass']);
			$field_class_matches = array_intersect($field_class, array('gform_column'));

			// if we have a column break field in a multi-column form, perform the list split
			if(!empty($form_class_matches) && !empty($field_class_matches)) {

				// we'll need to retrieve the form's properties for consistency
				$form = RGFormsModel::add_default_properties($form);
				$description_class = rgar($form, 'descriptionPlacement') == 'above' ? 'description_above' : 'description_below';

				// close current field's li and ul and begin a new list with the same form properties
				return '</li></ul><ul class="gform_fields '.$form['labelPlacement'].' '.$description_class.' '.$field['cssClass'].'"><li class="gfield gsection">';

			}
		}
	}

	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:

html
<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 name="input_2" id="input_1_2" type="text" value="" class="medium" tabindex="1">
		</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 name="input_3" id="input_1_3" type="text" value="" class="medium" tabindex="2">
		</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 name="input_5" id="input_1_5" class="textarea medium" tabindex="3" rows="10" cols="50"></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:

css
.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!

11 thoughts on “Multi-Column Gravity Forms

  1. This is awesome! Very useful. Thanks, Jordan.

    For anyone else reading this, you can enable multiple column sizes by adding a new item to the $field_class_matches array and then update the CSS.

    Example:
    functions.php
    $field_class_matches = array_intersect($field_class, array('gform-column', 'gform-one-column'));

    style.css
    .gform_wrapper.two-column_wrapper ul.gform_fields.gform-one-column {
    display: block;
    float: left;
    width: 100%;
    }

    • Excellent point! That was my intention of comparing class matches with a list of class names instead of just one.

      However it might make more sense to define the number of columns at the form level by assigning a custom class to the form itself and adding that class to the list of valid form classes:

      $form_class_matches = array_intersect($form_class, array('two-column', 'three-column'));
  2. Thank you for this tutorial! I have been trying to figure this out.

    In that vain, I can’t get the code as presented to work. I’m sure it’s because I didn’t put the proper info into my form settings of my form. In my section breaks, I have the css classname of “gform_column” – is that incorrect? Do I need to set a style name for the form itself too?

  3. Thanks for the great post. I have tried it but it doesn’t really work for me. First of all the structure of my Gform looks a bit different, because I want the first form fields to appear in just one column and then add the section break to format all the fields after the break as two columns with float. However, if I split my form, only the fields before the split are being submitted.

    Secondly, I was wondering if this function does also work with the honeypot anti-spam field that adds the gform validation wrapper at the end?

    • Hey Tim, are you sure you’re injecting the correct opening/closing HTML tags with the gform_field_content filter. That’s the only thing I can think of that would cause an entire column to not show up.

      I haven’t tested the honeypot anti-spam Gravity Forms addition myself but I don’t see how this would affect it at all.

  4. Any way to give the second column it’s own div name? For example, both columns are called “gform_column” i’d like the left one to be “gform_column1″ and the right one to be “gform_column2″ so that I can style each of them separately. is this possible?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>