Drupal Views exposed filters tend to accumulate controls.
A basic search form may start with a keyword field and a few filters. Add sorting and an items-per-page selector, and Drupal naturally renders everything as part of the same exposed form.
That makes sense structurally. It does not always make sense visually.
Sorting often belongs above the results. Items per page may belong next to pagination. Filters might live in a sidebar or drawer.
The HTML form attribute gives us a simple way to separate those concerns.
Form controls do not have to live inside the form
Most of the time, an input belongs to the <form> that contains it.
But HTML allows controls to explicitly reference a form by ID:
<form id="search-form"> <input name="keywords"> <button type="submit">Search</button> </form> <select name="sort" form="search-form"> <option value="date">Date</option> <option value="title">Title</option> </select>
The <select> can live anywhere in the document and will still participate in search-form when it is submitted.
That is particularly useful with Drupal Views exposed filters.
Instead of forcing every exposed control into one visual group, Twig can put them where they make sense:
{{ exposed|without('sort_by', 'items_per_page') }} <div class="results-sort"> {{ exposed.sort_by }} </div> {{ rows }} <div class="results-footer"> {{ pager }} {{ exposed.items_per_page }} </div>
Then a form alter can associate those controls with the original exposed form:
/** * Implements hook_form_views_exposed_form_alter(). */ function example_form_views_exposed_form_alter( array &$form, FormStateInterface $form_state, string $form_id, ): void { foreach (['sort_by', 'items_per_page'] as $key) { if (isset($form[$key])) { $form[$key]['#attributes']['form'] = $form['#id']; } } }
Drupal still owns the form. The browser still understands which controls belong to it. The template gets considerably more freedom.
The same technique can help with controls in sticky toolbars, dialog footers, complex search layouts, or other interfaces where form controls need to appear outside their natural DOM container.
There are a few tradeoffs
Moving controls outside the form changes more than layout.
JavaScript that relies on closest('form') will no longer work. CSS such as form select will not match detached controls. Events from those controls also do not bubble through the form element because the form is no longer their DOM ancestor.
The form ID also becomes part of the implementation contract, which matters when multiple Views or exposed forms appear on the same page.
These are manageable constraints, but they are worth documenting.
The form attribute gives us form ownership, not DOM nesting.
Maybe this should be contrib
There is also a small but interesting Drupal contrib opportunity here.
A module could allow site builders to configure which exposed Views elements should receive a form attribute and which should autosubmit.
The theme would remain responsible for placement. The module would simply provide the form association and optional behavior.
That could eliminate a recurring bit of project-specific PHP and JavaScript while relying primarily on native browser behavior.
For a relatively obscure HTML attribute, form opens up a useful amount of flexibility in Drupal Views. It lets the markup follow the interface instead of forcing the interface to follow the form.
For additional information on the form attribute, checkout the docs.
Read This Next
- The Cost of Waiting: Why CMS Maintenance Belongs in Every Website Budget
- Who Owns the Icon? Building Author-Friendly Icon Systems in Drupal
- Choosing a Multisite Approach in Drupal
- A/B Testing in Drupal Without the Enterprise Price Tag: A Practical Guide Using the A/B Test JS Module
- Using AI to Moderate Content in an Existing Drupal Workflow