Add class to form-tag in in views exposed form via template_preprocess_views_exposed_form() I wonder how I can add a class to the form tag (of the _search_content_ view's) exposed form using template_preprocess_views_exposed_form() (or even better template_preprocess_views_exposed_form__search_content()). The form is exposed as block.

It works so far using the following code in MY_THEME.theme:

function MY_THEME_preprocess_form(&amp;$variables) {
  if ($variables['element']['#form_id'] == 'views_exposed_form' &amp;&amp; $variables['element']['#view_id'] == 'search_content') {
    $variables['attributes']['class'][] = 'row';
  }
}


But I can't get it work for:

function MY_THEME_preprocess_views_exposed_form__search_content(&amp;$variables) {
  // I tried:
  // $variables['attributes']['class'][] = 'does-not-work';

  // and also:
  // $variables['attributes'] = new Attribute($variables['attributes']);
  // $variables['attributes']-&gt;addClass('does-not-work');

  // and also manipulating $variables['form'], but this didn't work either.
}


The function gets called, but it's not adding the class to the form tag. Is it possible to get it work with template_preprocess_views_exposed_form()?

Screenshot of kint($variables) output, for each function:



Is it possible to get it work with template_preprocess_views_exposed_form()?
Short version: You cannot use hook_preprocess_views_exposed_form() to modify the &lt;form&gt; tag. The &lt;form&gt; tag is independently rendered by a form theme hook set through the #theme_wrappers render property. Which means that it is completely disassociated from the actual views_exposed_form theme hook that renders the (internal) content of the views exposed form.

Long version:


views_theme() defines the views_exposed_form theme hook as returning a form render element. That means that it will eventually be using (unless somehow overridden) the definition provided by the Form render element. If you take a look at that, you will see that that definition  sets the'#theme_wrappers' property to ['form']. No surprises so far. :-)
At some point during the theming of a views page (or block), the theme hook views_view comes into play; this theme hook contains the exposed render variable that is essentially the exposed form you are interested in. The render array of exposed holds the following two relevant properties:


#theme =&gt; views_exposed_form (and other more specific ones like views_exposed_form__search_content): This is the theme hook that will provide the content of the form, i.e. everything inside the &lt;form&gt; tag. This is what you get access to and given the option to modify when calling template_preprocess_views_exposed_form(). This theme hook is not responsible for rendering the &lt;form&gt; tag and does not allow you to change it.
#theme_wrappers =&gt; ['form'] : This is the #theme_wrappers list of theme hooks; form will provide the actual &lt;form&gt; tag. It will essentially enclose the markup generated by the #theme theme hook into a &lt;form&gt; tag. This is what you get access to when calling template_preprocess_form(). This theme is responsible for rendering the &lt;form&gt; tag and does allow you to change it.



Implementation suggestion 

If you would rather let hook_form_alter() implementations handle form-related logic, you could still use another preprocess hook to implement the functionality you want, namely the preprocess_views_view() hook.

function MY_THEME_preprocess_views_view(&amp;$variables) {
  if ($variables['id'] === 'search_content') {
    $variables['exposed']['#attributes']['class'][] = 'row';
  }
}


Good luck, this is a really good question!