Skip to main content

Drupal form scaffolding for front-end developers

Sep 25 '15

Drupal form scaffolding

This guide explains how to create form scaffolding utilizing the grid system as opposed to creating new CSS styles for each form element. In Drupal, it can be very tempting to create styles using the form id. This often reduces the opportunity for modular styling and limits our access as ids generally carry more weight in CSS. This article assumes you are a front-end developer working closely with backend developers or you are a backend developer who understands how to construct forms. We will not discuss the PHP/Drupal functions, but rather controlling the markup on the Drupal form.

Where to start

First, you must find out how the form element is getting created and where it's being created. Account related forms like sign in/sign up are part of Drupal's core, but any other subsequent forms have been created in a module.

Example:
The cart currently has forms for the shipping and billing pages. These forms are created in the sites/all/modules/custom/example_cart folder. This module has several includes but has an include specifically for the forms called example_cart.forms.inc.

For the sake of theming, we're only looking for the place where the forms originate. Here's an example of what two forms that contain billing and shipping information may look like in our example_cart.inc file.

function example_cart_billing_form($form, &$form_state)
function example_cart_shipping_form($form, &$form_state)

These functions create the billing and shipping form elements. Inside you will find things like payment options, shipping address options, etc. It's important to note that you may want to include other modules or functionality into your forms. Let's say we have already built a module that contains address form items:

module_load_include('inc', 'bc_address', 'bc_address.forms');

This module is including the address fields from the address module's forms include file. In order to theme these fields from the cart section, we now need to run dpm($form);  in order to view the contents.

Adding basic containers to divide elements

First, go to the bottom of the form right below the return $form; and add dpm($form); to see exactly what the $form variable is rendering. I always begin theme work on the forms by adding a dpm to see what's inside of the form.
If you wish to divide the content into specific div containers, you will need to do a little rearranging of the current form elements as follows.

On the shipping form, I created a container specifically for the left side form elements. Utilizing the available Form API elements, I created a new array element.

Before

$form['shipping'] = array(
'#type' => 'fieldset',
'#title' => t('Shipping Information'),
);

After

$form['shipping_container'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array('bc-cart-form-container'),
),
);
$form['shipping_container']['shipping'] = array(
'#type' => 'fieldset',
'#title' => t('Shipping Information'),
);

As you can see above, I created the element shipping_container and made the #type a container element. The Form API lists the container under "Special Elements" and this allows you to add a wrapper div around elements. I add a class to the new shipping container which I've used across all of the bc-cart forms. Anything that was previously listed under the shipping form element needs to now be appended to the shipping_container element.

Before

$form['shipping']['save'] = array(
'#type' => 'checkbox',
'#title' => t('Save address to my address book'),
'#weight' => 100,
);

After

$form['shipping_container']['shipping']['save'] = array(
'#type' => 'checkbox',
'#title' => t('Save address to my address book'),
'#weight' => 100,
);

Adding your Grid Scaffolding

You can add your grid scaffolding to the form includes but I prefer to add the styles where the form gets rendered. This way you can separate the styles from the actual form element. For instance, the shipping form will ultimately get rendered on the shipping page but what if we need the shipping form later on inside of a modal or on a different page? We would want to preserve the html elements without scaffolding interfering.

We'll now remove our dpm after we've created some new containers and look for where the shipping content is rendered.

In the case of the checkout shipping page, we currently have an include file checkout_shipping.inc rendering the shipping content. In the final render content for the page, add your new dpm to see what $content is rendering. Inside of the dpm, you'll find the containers previously added and the contents on the shipping forms. Each of these elements can be used to add grid scaffolding.

Prefix/Suffix

// Grid 24 scaffolding first name and last name.
$shipping['first_name']['#prefix'] = '</pre>
<div class="bc-cart-form-row clearfix">
<div class="bc-cart-form-col col-sm-12 col-md-24">'; $shipping['first_name']['#suffix'] = '</div>
'; $shipping['last_name']['#prefix'] = '
<div class="bc-cart-form-col col-sm-12 col-md-24">'; $shipping['last_name']['#suffix'] = '</div>
</div>
<!-- /.bc-cart-form-row -->';

By utilizing the prefix/suffix attributes, we can add wrap specific form elements to behave exactly as we need them.

Adding Classes to Elements

If you want to add a class to an element, add an empty `[ ]` to the class element to add additional classes. Without the open bracket, it will erase the previous classes and add the new ones.

$content['shipping_form']['#attributes']['class'][] = 'bc-cart-forms js-bc-cart-checkout-form clearfix';

References
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7
https://api.drupal.org/api/drupal/includes!form.inc/group/form_api/7