Skip to main content
Drupal is a registered trademark of Dries Buytaert
Release: Drupal 11.4.6 Update released for Drupal core (11.4.6)! Release: Drupal 10.6.16 Update released for Drupal core (10.6.16)! Release: Drupal 12.0.0-alpha1 First alpha version released for Drupal core (12.0.0-alpha1). Release: AI (Artificial Intelligence) 1.5.0-rc3 New release candidate for module ai (1.5.0-rc3). Release: User Registration Link Pop Up 1.2.5 Minor update available for module url_popup (1.2.5). Release: User Registration Link Pop Up 1.2.4 Minor update available for module url_popup (1.2.4). Release: Smart Image Optimizer 1.0.1 Minor update available for module smart_image_optimizer (1.0.1). Release: Content Freshness Report 1.0.3 Minor update available for module content_freshness_report (1.0.3). Usage Milestone: Menu Condition Module menu_condition crossed 1,000 active installs. Module Revived: EzContent API - Enhanced De-coupled CMS Experience 2.3.9 Module ezcontent_api updated after 15 months of inactivity (2.3.9).

Category Filter

No security coverage Drupal 10–11
View on drupal.org

Category picker

Introduction

A drill-down + searchable modal for choosing an entry from a large hierarchy — taxonomy terms, or any content entity type that has a self-referencing parent entity-reference field.

Requirements

  • Drupal 10.3+ or Drupal 11.
  • No non-core dependencies for the main module. The taxonomy fast-path is used automatically when the target entity type is taxonomy_term.
  • Submodules: category_picker_views requires core Views; category_picker_facets requires the contributed Facets module.

Installation

Install as you would any Drupal module (composer require drupal/category_picker, then enable at Admin » Extend). Enable the category_picker_views and/or category_picker_facets submodules only if you need those integrations.

Configuration

  1. Add or edit an entity_reference field pointing at a hierarchical target (taxonomy vocabulary, or any entity type with a self-referencing parent field).
  2. At Manage form display, set the widget to Category picker (modal) and adjust its settings (display mode, hierarchy field, which categories are selectable, separator, search threshold, modal size/title).
  3. Optionally, at Manage display, set the formatter to Ancestor path (breadcrumb).
  4. For the Views filter: add the “… (category picker modal)” filter to a view. For the Facets widget: set a facet's widget to Category tree (category picker) and enable Facets' Transform entity ID to label and Hierarchy processors.

There is no global settings page — everything is per field / per view / per facet.

What it ships

Component Plugin id Use Form element category_picker #type => 'category_picker' in any form Field widget category_modal “Category picker (modal)” on any entity_reference field (single or multi-value) Field formatter entity_reference_hierarchy_path renders the value as Root › Branch › Leaf Views filter (submodule category_picker_views) category_picker exposed filter whose value form is the modal Facets widget (submodule category_picker_facets) category_picker_tree hierarchical tree facet

The form element

<?php
$form['category'] = [
  '#type' => 'category_picker',
  '#title' => $this->t('Category'),
  '#target_type' => 'taxonomy_term',   // any entity type with a parent field
  '#display_mode' => 'modal',          // modal | inline
  '#bundles' => ['categories'],        // optional; empty = all bundles
  '#parent_field' => 'parent',         // self-referencing hierarchy field
  '#leaf_mode' => 'no_children',       // no_children | boolean_field | all
  '#leaf_field' => '',                 // boolean field name for leaf_mode=boolean_field
  '#cardinality' => 1,                 // 1 | -1 | N
  '#separator' => ' &rsaquo; ',
  '#min_chars' => 2,
  '#dialog_width' => 640,
  '#dialog_title' => $this->t('Choose a category'),
  '#default_value' => 42,              // id, or [id, id, &hellip;] when multi-value
];
?>

The element is self-contained: after every pick or removal it refreshes its own markup through a hidden update submit — the host form needs no #ajax. Value is an int (single) or int[] (multi).

On a multi-value element the selected entries render as a native Drupal tabledrag table (drag handle, hidden _weight per row, “Show row weights” toggle) styled by the admin theme, and the modal opener sits in a &lt;div class="field-actions"&gt; labelled Add another item — the same chrome core uses for its own multi-value fields. Drag order is folded into the value on any widget submit; hook_category_picker_order_alter() fires when it changes.

The field widget

Attach any entity_reference field to a hierarchical target, then on Manage form display pick Category picker (modal). Target bundles and sort come from the field's own reference settings. Widget settings: display mode (pop-up dialog, or an inline tree always visible under the field), hierarchy field, which categories can be picked (leaf mode / leaf field), path separator, search minimum characters, modal width and title. When leaf mode is “only categories flagged as selectable” the leaf-field name is validated on save — it must be a real boolean field on the target entity type. The Modal title setting names the dialog only; on a multi-value field the opener button always reads “Add another item”.

If the module is uninstalled the field falls back to Drupal's default entity-reference widget.

The Facets tree widget

Enable category_picker_facets, then set the facet's widget to Category tree (category picker). For names instead of raw ids, also enable the facet's Transform entity ID to label (translate_entity) processor and the Hierarchy processor.

This widget renders through core Facets' own LinksWidget and theme hooks (facets_result_item, facets_item_list, …) — it does not use any of this module's category_picker_* theme hooks or template suggestions below, and never touches the form element's selected-values table. To restyle it, follow Facets' own theming/template-override conventions, not this module's.

Multilingual

The form element, widget, and entity_reference_hierarchy_path formatter follow the active content language: every label, the drill-down and breadcrumb, the selected-row / chip labels, search matching, and label sorting are resolved through EntityRepository::getTranslationFromContext(). Search only matches a category whose label in the active language contains the term — a hit found solely through another translation is not shown. Modal/AJAX responses and the path formatter carry languages:language_content (+ languages:language_interface) cache contexts, so each language caches independently.

Entity types that are not translatable (or a hierarchy with translation disabled) are unaffected — resolution is a no-op there.

The Facets tree widget is separate: it still needs Facets' own Transform entity ID to label (translate_entity) processor for translated names, as noted above.

Hooks

See category_picker.api.php for full docs. All take the read-only PickerContext as context.

  • hook_category_picker_query_alter(QueryInterface $query, PickerContext $context, ?int $parent_id) — alter the entity query for one level/search. Not invoked for taxonomy_term targets with no bundle restriction (they use TermStorage's fast tree-loading path instead of building a query).
  • hook_category_picker_row_alter(array &amp;$row, EntityInterface $entity, PickerContext $context) — alter one drill-down row's data (label, selectability, path, …).
  • hook_category_picker_breadcrumb_alter(array &amp;$crumbs, ?int $parent_id, PickerContext $context) — alter the breadcrumb trail.
  • hook_category_picker_search_results_alter(array &amp;$entities, string $search_string, PickerContext $context) — alter/filter the matched entities for a search.
  • hook_category_picker_path_alter(string &amp;$path, array $ancestors, PickerContext $context) — alter the assembled “Root › … › Leaf” path string.

The four row/breadcrumb/search/path hooks all run on already-loaded entities, so unlike the query hook they apply identically regardless of the taxonomy fast path.

Theming

Every render layer has a themeable hook + .html.twig template, each with hook_theme_suggestions_HOOK_alter() suggestions of the form HOOK__ENTITYTYPE and HOOK__ENTITYTYPE__BUNDLE (most specific wins):

  • category_picker_modal — the dialog shell (search bar, back slot, body, actions).
  • category_picker_level — one drill-down level or a flat search-result list.
  • category_picker_back — the independently-swapped “back one level” link.
  • category_picker_path — the HierarchyPathFormatter read-only path display.

The multi-value widget's selected-values list is a native Drupal #type =&gt; 'table' with tabledrag reordering (no module theme hook) so it inherits the admin theme's styling; drag order is folded in via the row _weight selects on any widget submit.

Standards

phpcs --standard=Drupal,DrupalPractice, phpstan (level per drupal.org), eslint/stylelint with core's config. Tests under tests/src/.

Maintainers

Current maintainers are listed on the project page. Issues and merge requests are welcome in the project's issue queue.

Depends on

Dependencies of the latest stable release

No dependencies recorded for this project.

Required by

Tracked projects that depend on this one

No tracked projects depend on this one yet.

Activity

Tracked releases
1
Tracked since
Sep 2026
Latest release
8 hours ago
Releases (12 mo)
1 ▲ from 0
Maintenance
Active

Releases

Version Type Core Release date
1.0.0 Stable 10–11 Sep 3, 2026