I’m slowly moving along on my first Drupal 8 project. After getting annoyed enough with the look of the login form, I decided to update my form templates to use Bootstrap 3 styles.
Notes
- I haven’t messed with size control yet, but I’m guessing that would need to be handled by field templates unless another module is installed to handle it.
- My
input–textfield.html.twig
,input–email.html.twig
, andinput–password.html.twig
templates are identical, so I could probably look into consolidating those somehow.
The Code
Here is the code I used to modify the form markup for Bootstrap compatibility.
.theme
Add the following code to your .theme
file:
function template_preprocess_form_element(&$variables) {
$element = $variables['element'];
// Get the title
if (isset($element['#title']) && $element['#title'] !== '') {
$variables['title'] = ['#markup' => $element['#title']];
}
// Modify the label variable
if (!empty($element['#type']) && in_array($element['#type'], array('checkbox', 'radio'))) {
// Set the label variable to just the title for checkbox and radio inputs
$variables['label'] = $variables['title'];
} else {
// Use default label rendering for any other inputs
$variables['label'] = array('#theme' => 'form_element_label');
$variables['label'] += array_intersect_key($element, array_flip(array('#id', '#required', '#title', '#title_display')));
}
}
form-element.html.twig
{%
set classes = [
'js-form-item',
'form-item',
'js-form-type-' ~ type|clean_class,
'form-item-' ~ name|clean_class,
'js-form-item-' ~ name|clean_class,
title_display not in ['after', 'before'] ? 'form-no-label',
disabled == 'disabled' ? 'form-disabled',
errors ? 'form-item--error',
type != 'radio' ? 'form-group',
type == 'checkbox' ? 'checkbox',
type == 'radio' ? 'radio',
]
%}
{%
set description_classes = [
'description',
description_display == 'invisible' ? 'visually-hidden',
'help-block',
]
%}
<div{{ attributes.addClass(classes) }}>
{% if label_display in ['before', 'invisible'] and type not in ['checkbox', 'radio'] %}
{{ label }}
{% endif %}
{% if prefix is not empty %}
<span class="field-prefix">{{ prefix }}</span>
{% endif %}
{% if description_display == 'before' and description.content %}
<div{{ description.attributes }}>
{{ description.content }}
</div>
{% endif %}
{% if type in ['checkbox', 'radio'] %}
<label>
{{ children }} {{ label }}
</label>
{% elseif type == 'item' %}
<div>{{ children }}</div>
{% else %}
{{ children }}
{% endif %}
{% if suffix is not empty %}
<span class="field-suffix">{{ suffix }}</span>
{% endif %}
{% if label_display == 'after' and type not in ['checkbox', 'radio'] %}
{{ label }}
{% endif %}
{% if errors %}
<div class="form-item--error-message">
{{ errors }}
</div>
{% endif %}
{% if description_display in ['after', 'invisible'] and description.content %}
<div{{ description.attributes.addClass(description_classes) }}>
{{ description.content }}
</div>
{% endif %}
</div>
input–textfield.html.twig
{%
set classes = [
'form-control',
]
%}
<input{{ attributes.addClass(classes) }} />{{ children }}
input–email.html.twig
{%
set classes = [
'form-control',
]
%}
<input{{ attributes.addClass(classes) }} />{{ children }}
input–password.html.twig
{%
set classes = [
'form-control',
]
%}
<input{{ attributes.addClass(classes) }} />{{ children }}
input–submit.html.twig
{%
set classes = [
'btn',
'btn-default',
]
%}
<input{{ attributes.addClass(classes) }} />{{ children }}
radios.html.twig
{%
set classes = [
'form-group',
]
%}
<div{{ attributes.addClass(classes) }}>{{ children }}</div>
select.html.twig
{%
set classes = [
'form-control',
]
%}
{% spaceless %}
<select{{ attributes.addClass(classes) }}>
{% for option in options %}
{% if option.type == 'optgroup' %}
<optgroup label="{{ option.label }}">
{% for sub_option in option.options %}
<option value="{{ sub_option.value }}"{{ sub_option.selected ? ' selected="selected"' }}>{{ sub_option.label }}</option>
{% endfor %}
</optgroup>
{% elseif option.type == 'option' %}
<option value="{{ option.value }}"{{ option.selected ? ' selected="selected"' }}>{{ option.label }}</option>
{% endif %}
{% endfor %}
</select>
{% endspaceless %}
textarea.html.twig
{%
set classes = [
'form-control',
]
%}
<div{{ wrapper_attributes }}>
<textarea{{ attributes.addClass(classes) }}>{{ value }}</textarea>
</div>