3 namespace Drupal\Core\Render\Element;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\Core\Render\Element;
9 * Provides a render element for vertical tabs in a form.
11 * Formats all child and non-child details elements whose #group is assigned
12 * this element's name as vertical tabs.
15 * - #default_tab: The HTML ID of the rendered details element to be used as
16 * the default tab. View the source of the rendered page to determine the ID.
20 * $form['information'] = array(
21 * '#type' => 'vertical_tabs',
22 * '#default_tab' => 'edit-publication',
25 * $form['author'] = array(
26 * '#type' => 'details',
27 * '#title' => $this->t('Author'),
28 * '#group' => 'information',
31 * $form['author']['name'] = array(
32 * '#type' => 'textfield',
33 * '#title' => $this->t('Name'),
36 * $form['publication'] = array(
37 * '#type' => 'details',
38 * '#title' => $this->t('Publication'),
39 * '#group' => 'information',
42 * $form['publication']['publisher'] = array(
43 * '#type' => 'textfield',
44 * '#title' => $this->t('Publisher'),
48 * @FormElement("vertical_tabs")
50 class VerticalTabs extends RenderElement {
55 public function getInfo() {
56 $class = get_class($this);
60 [$class, 'processVerticalTabs'],
63 [$class, 'preRenderVerticalTabs'],
65 '#theme_wrappers' => ['vertical_tabs', 'form_element'],
70 * Prepares a vertical_tabs element for rendering.
72 * @param array $element
73 * An associative array containing the properties and children of the
74 * vertical tabs element.
77 * The modified element.
79 public static function preRenderVerticalTabs($element) {
80 // Do not render the vertical tabs element if it is empty.
81 $group = implode('][', $element['#parents']);
82 if (!Element::getVisibleChildren($element['group']['#groups'][$group])) {
83 $element['#printed'] = TRUE;
89 * Creates a group formatted as vertical tabs.
91 * @param array $element
92 * An associative array containing the properties and children of the
94 * @param \Drupal\Core\Form\FormStateInterface $form_state
95 * The current state of the form.
96 * @param array $complete_form
97 * The complete form structure.
100 * The processed element.
102 public static function processVerticalTabs(&$element, FormStateInterface $form_state, &$complete_form) {
103 if (isset($element['#access']) && !$element['#access']) {
107 // Inject a new details as child, so that form_process_details() processes
108 // this details element like any other details.
109 $element['group'] = [
110 '#type' => 'details',
111 '#theme_wrappers' => [],
112 '#parents' => $element['#parents'],
115 // Add an invisible label for accessibility.
116 if (!isset($element['#title'])) {
117 $element['#title'] = t('Vertical Tabs');
118 $element['#title_display'] = 'invisible';
121 $element['#attached']['library'][] = 'core/drupal.vertical-tabs';
123 // The JavaScript stores the currently selected tab in this hidden
124 // field so that the active tab can be restored the next time the
125 // form is rendered, e.g. on preview pages or when form validation
127 $name = implode('__', $element['#parents']);
128 if ($form_state->hasValue($name . '__active_tab')) {
129 $element['#default_tab'] = $form_state->getValue($name . '__active_tab');
131 $element[$name . '__active_tab'] = [
133 '#default_value' => $element['#default_tab'],
134 '#attributes' => ['class' => ['vertical-tabs__active-tab']],
136 // Clean up the active tab value so it's not accidentally stored in
138 $form_state->addCleanValueKey($name . '__active_tab');