Gravity Forms Bootstrap 5 Styling
By default, Gravity Forms does not support Bootstrap classes out of the box, so the two don’t end up working very well together. The included Gravity Forms CSS includes too many styles that need to be overridden, this is why instead of applying Bootstrap styles directly, we tweaked Gravity Forms to add default Bootstrap markup.
<?php | |
/** | |
* @snippet Gravity Form Bootstrap 5 Markup | |
* @author Prosvit Design Team | |
* @website https://prosvit.design | |
*/ | |
/** | |
* Filters form field containers | |
* Adds Bootstrap Grid classes to containers | |
*/ | |
add_filter('gform_get_form_filter', 'prosvit_design_add_bootstrap_grid_row_markup', 10, 2); | |
function prosvit_design_add_bootstrap_grid_row_markup($form_string, $form) | |
{ | |
return str_replace('gform_fields', 'gform_fields row', $form_string); | |
} | |
add_filter('gform_field_container', 'prosvit_design_add_bootstrap_grid_columns_markup', 10, 6); | |
function prosvit_design_add_bootstrap_grid_columns_markup($field_container, $field, $form, $css_class, $style, $field_content) | |
{ | |
if (is_admin()) { | |
return $field_container; | |
} | |
$css_class .= ' col-12 mb-3'; | |
if (!strpos($css_class, 'gfield--width-full')) { | |
$css_class .= ' col-md'; | |
} | |
return '<div class="' . $css_class . '">' . $field_content . '</div>'; | |
} | |
/** | |
* Filters form fields | |
* Adds Bootstrap classes to input, textarea, select, radio | |
*/ | |
add_filter('gform_field_content', 'prosvit_design_add_bootstrap_fields_markup', 10, 2); | |
function prosvit_design_add_bootstrap_fields_markup($field_content, $field) | |
{ | |
if (is_admin()) { | |
return $field_content; | |
} | |
$bootstrap_classes = array( | |
'text' => [ | |
'tag' => 'form-control', | |
'label' => 'form-label', | |
'text' => 'form-text', | |
], | |
'number' => [ | |
'tag' => 'form-control', | |
'label' => 'form-label', | |
'text' => 'form-text', | |
], | |
'textarea' => [ | |
'tag' => 'form-control', | |
'label' => 'form-label', | |
'text' => 'form-text', | |
], | |
'name' => [ | |
'tag' => 'form-control', | |
'label' => 'form-label', | |
'text' => 'form-text', | |
], | |
'select' => [ | |
'tag' => 'form-select', | |
'label' => 'form-label', | |
'text' => 'form-text', | |
], | |
'checkbox' => [ | |
'tag' => 'form-check-input', | |
'label' => 'form-check-label', | |
'text' => 'form-text', | |
], | |
'radio' => [ | |
'tag' => 'form-check-input', | |
'label' => 'form-check-label', | |
'text' => 'form-text', | |
], | |
); | |
$tags = array( | |
'text' => 'input', | |
'number' => 'input', | |
'checkbox' => 'input', | |
'radio' => 'input', | |
'name' => 'input', | |
'textarea' => 'textarea', | |
'select' => 'select' | |
); | |
$dom = new DOMDocument(); | |
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $field_content); | |
// Labels - add "form-label/form-check-label" class | |
$labels = $dom->getElementsByTagName('label'); | |
if ($labels) { | |
foreach ($labels as $label) { | |
$class_label = $label->getAttribute('class'); | |
$class_label_new = (array_key_exists($field->type, $bootstrap_classes)) ? $bootstrap_classes[$field->type]['label'] : ''; | |
$label->setAttribute('class', $class_label_new . ' ' . $class_label); | |
} | |
} | |
// Divs | |
// Descriptions - add "form-text/invalid-feedback" class | |
$divs = $dom->getElementsByTagName('div'); | |
foreach ($divs as $div) { | |
$class = $div->getAttribute('class'); | |
$class_new = []; | |
$class_new[] = $class; | |
// Descriptions | |
if (strpos($class, 'gfield_description') !== false) { | |
$class_new[] = (array_key_exists($field->type, $bootstrap_classes)) ? $bootstrap_classes[$field->type]['text'] : ''; | |
} | |
// Validation | |
if ($field->failed_validation) { | |
$class_new[] = 'is-invalid'; | |
} | |
if (strpos($class, 'gfield_validation_message') !== false) { | |
$class_new[] = 'invalid-feedback'; | |
} | |
// Checkboxes & Radios | |
if (strpos($class, 'gchoice') !== false) { | |
$class_new[] = 'form-check'; | |
} | |
$div->setAttribute('class', implode(' ', $class_new)); | |
} | |
// Tags - add "form-control/form-select/form-check-input" class | |
$field_type_tag = (array_key_exists($field->type, $tags)) ? $tags[$field->type] : null; | |
$field_tags = !empty($field_type_tag) ? $dom->getElementsByTagName($field_type_tag) : null; | |
if (!empty($field_tags)) { | |
foreach ($field_tags as $field_tag) { | |
$class = $field_tag->getAttribute('class'); | |
$class_new = []; | |
$class_new[] = $class; | |
// Tag class | |
if (array_key_exists($field->type, $bootstrap_classes)) { | |
$class_new[] = $bootstrap_classes[$field->type]['tag']; | |
} | |
// Validation class | |
if ($field->failed_validation) { | |
$class_new[] = 'is-invalid'; | |
} | |
$field_tag->setAttribute('class', implode(' ', $class_new)); | |
// Checkboxes & Radios required tag | |
if ($field->isRequired) { | |
$field_tag->setAttribute('required', 'required'); | |
} | |
} | |
} | |
return $dom->saveHtml(); | |
} | |
/** | |
* Filters the next, previous and submit buttons. | |
* Replaces the forms <input> buttons with <button> while maintaining attributes from original <input>. | |
* Adds Bootstrap btn and btn-primary classes | |
*/ | |
add_filter('gform_next_button', 'prosvit_design_add_button_bootstrap_markup', 10, 2); | |
add_filter('gform_previous_button', 'prosvit_design_add_button_bootstrap_markup', 10, 2); | |
add_filter('gform_submit_button', 'prosvit_design_add_button_bootstrap_markup', 10, 2); | |
function prosvit_design_add_button_bootstrap_markup($button, $form) | |
{ | |
$dom = new DOMDocument(); | |
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $button); | |
$input = $dom->getElementsByTagName('input')->item(0); | |
$new_button = $dom->createElement('button'); | |
$new_button->appendChild($dom->createTextNode($input->getAttribute('value'))); | |
$input->removeAttribute('value'); | |
foreach ($input->attributes as $attribute) { | |
// Add class btn btn-primary | |
if ($attribute->name == 'class') { | |
$attribute->value .= ' btn btn-primary'; | |
} | |
$new_button->setAttribute($attribute->name, $attribute->value); | |
} | |
$input->parentNode->replaceChild($new_button, $input); | |
return $dom->saveHtml($new_button); | |
} | |
/** | |
* Bootstrap Form Validation | |
*/ | |
add_action('wp_footer', 'prosvit_design_add_bootstrap_js_validation'); | |
function prosvit_design_add_bootstrap_js_validation() | |
{ ?> | |
<script> | |
jQuery(document).bind('gform_post_render', function(e, formID) { | |
if (!jQuery('.gform_validation_errors').length) { | |
return; | |
} | |
const form = document.getElementById('gform_' + formID); | |
form.classList.add('was-validated'); | |
}); | |
</script> | |
<?php } |
Features
- Applies Bootstrap classes to common field types – input, select, textarea, checks & radios ( .form-control, .form-select, .form-label, etc. )
- Applies Bootstrap classes to the submit button ( .btn, .btn-primary, etc. )
- Applies Bootstrap classes to columns ( .col, .col-md, etc. )
- Supports Gravity Forms validation
Usage and Settings
A. Disable the output of the default Gravity Forms CSS.
- Set Output CSS to No
- Set Output HTML5 to Yes
B. Requires Bootstrap to be in use by the theme – https://getbootstrap.com/docs/5.0/getting-started/download/.
Does this snippet (still) work?
Please let us know in the comments if everything worked as expected. We would be happy to revise the snippet if you report otherwise (please provide screenshots).