Multi-Column Gravity Forms With CSS

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 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:

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 multi-column form classes
			$form_class = explode(' ', $form['cssClass']);
			$form_class_matches = array_intersect($form_class, array('two-column', 'three-column'));

			// check for the presence of section break column classes
			$field_class = explode(' ', $field['cssClass']);
			$field_class_matches = array_intersect($field_class, 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
				$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 field list classes
				return '</li></ul><ul class="gform_fields '.$form['labelPlacement'].' '.$description_class.' '.$field['cssClass'].'"><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:

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 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:

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!

26 thoughts on “Multi-Column Gravity Forms With CSS

  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?

  5. Hi there excelent tutorial, but im having trouble getting it to work. Im adding the function in the functions.php of my child theme but it doesn´t seem to work. is that the only thing i have to do or do i have to set an especific class to the form itself and/or to the section break field? heres is a link of where im testing it: http://goo.gl/vyzi7k

    thanx in advance for the help!

    • nevermind, i think i got it to work. but one question about what greg ad it, do i have to add that line of code to the function or replace it for the one in this tutorial? thanx again

    • I mentioned the CSS ready classes in the opening paragraphs but their capability is limited. With those, all you can do is float individual fields left and right, not entire groups of fields.

  6. This did not work, after fixing three of the errors it posted in the log I gave up on it, hopefully Gravity Forms releases CSS for this in the future.

  7. This looks great to me, but for some reason the php just turns my form into a blank page. From a cut n’ paste attempt, I found that the &amp’s in the php needed to be replaced with &&, if that’s any help to anyone. And I found that my problem seems to be with the opening/closing HTML tags as Cameron already pointed out. My form doesn’t go blank if if I just use return’ ‘; instead of trying to return the the desired HTML. I also noticed that if I include /li and /ul tags in the return’ ‘ statement that the form page doesn’t go blank. But then the HTML markup is not showing any of the desired changes either. Sorry that this site I’m working on is not live. Any ideas?? Thanks

  8. Pingback: *Multi-Column Gravity Forms* http://www… | MotionBump
  9. Great tutorial! Customizations like this is exactly why we build things in such a way that 3rd party developers can customize Gravity Forms behavior.

    The ability to create multi-column forms directly within the Form Editor is a feature that we do plan on tackling in the future.

    We have already laid the groundwork that we needed to put in place within Gravity Forms v1.9 which was just released as a beta last weekend: http://www.gravityhelp.com/gravity-forms-v1-9-beta-1-released/

    With the changes we’ve made under the hood we’ll be able to tackle this functionality as a WYSIWYG feature of the Form Editor in a future feature version release.

  10. Depending on the situation something like this can work very nicely:

    #gform_fields_1 .gfield:nth-child(odd) {
    width:47.5%; margin-right:5%; display:inline-block;
    }
    #gform_fields_1 .gfield:nth-child(even) {
    width:47.5%; display:inline-block;
    }

    You will also probably have to target the different types of inputs to get their widths just right:
    #gform_wrapper_1 select { width:102%; }
    etc.

    And you can target particular pieces for exceptions like, say you want the textarea to be 100% and not columnized.

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>