1

Normal scenario

In a custom form (created using FAPI) I have a fieldset definition:

$company_field_set = [
  '#type'  => 'fieldset',
];

If I would like to customize the fieldset template, I normally would create a hook_theme_suggestions_HOOK_alter function to add suggestions and then overwrite the template.

Alternative

I was wondering though why I wouldn't simply use the #theme key, so I tried this:

$company_field_set = [
  '#type'  => 'fieldset',
  '#theme' => 'my_custom_company_fieldset',
];

This does indeed render my custom template instead of fieldset.html.twig, but I don't get any variables in it. I would expect it to behave just like fieldset.html.twig.

I have tried several theme definitions:

// Same as default fieldset
'my_custom_company_fieldset' => [
  'render element' => 'element',
]

// Another tryout
'my_custom_company_fieldset' => [
  'render element' => 'children',
]

My template currently looks like this:

{% extends 'fieldset.html.twig' %}

I also tried:

{{ children }}

I see the template contents (like static text and such), but no variables.

I think I know a little bit too little about this and am missing something somewhere. Could anyone point out my mistakes and/or tell me whether or not this is even possible?

2
  • 2
    If you have {{ children }} already rendered with no variables then this is usually a #theme_wrapper. This can be quite confusing and it is discussed to remove this from core, see drupal.org/project/drupal/issues/2714509 – 4k4 Oct 6 '20 at 8:40
  • Thanks! I indeed found this out myself, but I didn't know about this discussion. Good to know. – vrijdenker Oct 7 '20 at 14:32
1

After looking a little deeper in the Drupal core I found out that in this case I shouldn't overwrite #theme, but use #theme_wrappers instead.

So my theme definition:

function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'my_custom_fieldset' => [
      'render element' => 'children',
    ],
  ];
}

In my form:

$form['some_fieldset'] = [
  '#type'  => 'fieldset',
  '#title' => 'Some title',
  '#theme_wrappers' => ['my_custom_fieldset'],
];

$form['some_fieldset']['some_field1'] = [
  '#type' => 'textfield',
  '#title' => 'Some title',
];

$form['some_fieldset']['some_field2'] = [
  '#type' => 'textfield',
  '#title' => 'Another title',
];

And then my template my-custom-fieldset.html.twig:

<fieldset>{{children}}</fieldset>

Or for example:

<fieldset>
  {{ children.some_field1 }}
  Some customization here
  {{ children.some_field2 }}
  Something custom here
</fieldset>
0

Normal Solution (easy).

/*
 * Implements hook_theme_suggestions_HOOK_alter()
 */
function journey_talk_theme_suggestions_fieldset_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'fieldset__' . $variables['element']['#parents'][0];
}

Alternative Solution (doable, not recommended, you'll work harder).

First you need to declare theme and variable names in hook_theme()

function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'my_custom_company_fieldset' => [
      'variables' => ['my_var' => null],
    ],
  ];
}

Second, you set the variable value where you assign #theme (OR also in a preprocess function)

$form['book']['title'] = [
  '#type' => 'textfield',
  '#title' => $this->t('Title'),
];

$form['book']['publisher'] = [
  '#type' => 'textfield',
  '#title' => $this->t('Publisher'),
];

// You have to put your fieldset after your fields, otherwise they won't be inside $form['book'];
$form['book'] = [
  '#type' => 'fieldset',
  '#title' => $this->t('Book Info (type = fieldset)'),
  '#theme' => 'my_custom_company_fieldset',
  '#my_var' => $form['book'], // setting a value for the "my_var" variable declared in hook_theme()
];

and in twig you can render the fields with

{{ my_var.title }}

{{ my_var.publisher }}

But the downside of this approach is that you cant access all the existing variables available in fieldset.html.twig. Although, you could at the end of the day get access to those values through your variable (my_var) tree.

You know what the say, work smarter not harder! Thus, normal solution is the way to go.

3
  • Thanks for your answer. I understand everything you are saying: I have made themes before. However: fieldset.html.twig simply renders variable 'children', although it's not defined in it's theme-definition's varoables. Your answer doesn't answer why that works for fieldset and not for my custom theme? Where does variable 'children' magically come from? – vrijdenker Oct 6 '20 at 5:48
  • @vrijdenker like I mentioned in my answer, variables can also be declared & set in a preprocess function, so that happends in core right here. – No Sssweat Oct 6 '20 at 6:00
  • 1
    I know, but that's not how a default fieldset works. A fieldset simply renders it's children and that way renders all the fields that are in it. I just found out how it works and will post my answer. – vrijdenker Oct 6 '20 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.