I have created an implementation of

hook_theme_suggestions_form_element_alter()

in my THEMENAME.theme file:

function manager_theme_suggestions_form_element_alter(array &$suggestions, array $variables) {
  if (\Drupal::service('path.current')->getPath() == '/user/login') {
    $suggestions[] = $variables['theme_hook_original'] . '--user-login';
  }
}

Afterwards the template suggestion is correctly added to my suggested templates. I see that via my HTML markup in Chrome dev tools:

screenshot

However, if this template file (file name form-element--user-login.html.twig) is existing in my theme's templates-folder, it is never loaded by Drupal. Only the template from

core/themes/classy/templates/form/form-element.html.twig

is being used. If I create a template file with the name "form-element.html.twig" inside my own theme's template folder, I can override the template from the base theme. Only my own template suggestion does not work.

Since

hook_theme_suggestions_form_element_alter()

seems to be the correct place to alter template file suggestions, I consider this a core bug.

CommentFileSizeAuthor
template-suggestions.png83.27 KBjepster_

Comments

Peter Majmesku created an issue. See original summary.

jepster_’s picture

Issue summary: View changes
jepster_’s picture

Issue summary: View changes
jepster_’s picture

Issue summary: View changes
jepster_’s picture

I have figured out, how to work with the suggestions and the actual template. There need to be 2 functions.

1.,

hook_theme_suggestions_form_element_alter()

Just informs about template suggestions. It does not load the templates.

E.g.:

/**
 * Implementation of hook_theme_suggestions_form_element_alter().
 */
function manager_theme_suggestions_form_element_alter(array &$suggestions, array $variables) {
  if (\Drupal::service('path.current')->getPath() == '/user/login') {
    $suggestions[] = $variables['theme_hook_original'] . '--user-login';
  }
}

2.,

hook_preprocess_form_element()

Loads the template.

E.g.

/**
 * Implementation of hook_preprocess_form_element().
 */
function manager_preprocess_form_element(&$variables, $hook, &$info) {
  $info['template'] = 'form-element--user-login';
}
jepster_’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ygstnd’s picture

#5 works for me.

rromore’s picture

Note for future Googlers: you shouldn't need to define the `hook_preprocess_form_element` function. The `hook_theme_suggestions_form_element_alter` should use underscores instead of dashes for the suggestions array.

rick hood’s picture

I have similar problem

/**
 * Implements hook_theme_suggestions_HOOK() 
 */
function mytheme_theme_suggestions_form_alter(array &$suggestions, array $variables) {
    $suggestions[] = 'form__' . $variables['element']['#id'];
}

I can see the suggestion: form--views-exposed-form-search-global-page-1.html.twig ...and created that template file, but Drupal is not picking it up, still using: form.html.twig ...cleared cache a bunch.

volodymyr.oliinyk’s picture

#9 worked for me
I used only hook_theme_suggestions_form_element_alter and inside
$suggestions[] = str_replace('-','_',[DYNAMICALLY GENERATED SUGGESTION]);

rahul_k’s picture

you can also give a try for this module drupal.org/project/themable_forms

tsega’s picture

@rrmore comment is correct at #9; one should not use dashes `-` in template suggestion names but rather underscores `_`. So the following works as expected.

/**
 * Implementation of hook_theme_suggestions_form_element_alter().
 */
function manager_theme_suggestions_form_element_alter(array &$suggestions, array $variables) {
  if (\Drupal::service('path.current')->getPath() == '/user/login') {
    $suggestions[] = $variables['theme_hook_original'] . '__user_login';  // Notice the use of underscore 
  }
}
isalmanhaider’s picture

Version: 8.4.4 » 10.0.x-dev

You can also use this handy module https://www.drupal.org/project/formdazzle

Steppico’s picture

I had the same problem with form-element. It didn't have any theme suggestions, thus my hook_theme() for a custom template did not work.
I ended up solving it this way.

In MYMODULE.module:

function MYMODULE_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if(strpos($hook, 'form_element')){
    $suggestions[] = 'form_element__preview';
  }
}

I've seen other more generic solutions trying to add to the $suggestions array by checking whether another $suggestion for that theme existed. In the case of the form-element, we know that it doesn't have any suggestion, thus such solution wouldn't work. BUT form-element does exist in the $hook parameter. It is a string, so by using strpos(), it is possible to verify whether form-element exists in the string, and if so, insert a new suggestion.

Finally, to make it work, it is just required to implement the hook_theme():

 function MYMODULE_theme($existing, $type, $theme, $path) {
    $path_to_theme = $path . "/templates/form"; 
  return [
     "form_element__preview" => [
        'template' => 'form-element--preview',
        'base hook' => 'form-element',
        'path' => $path_to_theme,
      ]
    ];
 }

Hope it can help you achieve what you want.

martijn de wit’s picture

Version: 10.0.x-dev » 8.9.x-dev
Category: Bug report » Support request
drale01’s picture

#11 I don't know is it clear enough.
This was my code that didn't work:

function my_theme_theme_suggestions_alter(array &$suggestions, array $variables, $info)
{
  if ($variables['theme_hook_original'] == 'form_element_label')
  {
    $suggestions[] = 'form_element_label__'.$variables['element']['#id']);
  }
}

But when I put this line of code

 $id_item = str_replace('-', '_', $variables['element']['#id']);

it works.
So it looks like this:

function my_theme_theme_suggestions_alter(array &$suggestions, array $variables, $info)
{
  if ($variables['theme_hook_original'] == 'form_element_label')
  {
    $id_item = str_replace('-', '_', $variables['element']['#id']);
    $suggestions[] = 'form_element_label__'.$id_item;
  }
}