Skip to content

SearchKit Displays

SearchKit Displays are responsible for rendering the results of a SavedSearch query, either as html content, or in some other form.

Display Types

Each Display has a "type". Most types (Table, List, Grid) are intended to render as part of a webpage (see Embedding Displays), but a few types have specialized output such as an Autocomplete display which populates a form dropdown-select, or an Entity display which writes to a SQL table. Such displays which do not render markup belong to the "non-viewable" grouping.

Creating a New Display Type

An extension can add new display types in addition to the ones included with SearchKit (Table, List, etc).

For a complete step-by-step walkthrough, see Creating a Custom SearchDisplay Type.

At a high level, the process consists of:

  1. Adding the new display type to the search_display_type option list (typically using a managed entity).
  2. Creating an AngularJS module.
  3. Declaring the AngularJS module dependency and element export in the module's .ang.php file.
  4. Adding an admin component (ex: searchAdminDisplayList.component.js).
  5. Adding a display component (ex: crmSearchDisplayList.component.js).

Embedding Displays

It's often useful to place search displays into other contexts such as dashboards, tabs, modal popups, or standalone pages. This process is called embedding.

To render correctly, a SearchKit display requires its configuration settings. Any of the following three methods can be used to embed a display and supply these settings.

SearchKit leverages Afform for its embedding features. To prepare a SearchDisplay for embedding, first create an Afform (or place it in an existing Afform), and then embed that Afform in the desired place.

  • Use case: This method is preferable if you need to leverage Afform features such as user-facing filter fields, custom submit buttons, or complex layout grids.
  • AngularJS Module Required: The Afform itself (every Afform is a self-contained AngularJS module).
  • How it works: Under the hood, the AfformSearchMetadataInjector class injects the display configuration settings directly into the markup.

2. Using the SearchDisplay getMarkup API

You can call the SearchDisplay.getMarkup API action to generate the HTML markup for a search display. This saves the step of creating an Afform if only the search display is needed.

  • Use case: Preferable for programmatic backend embedding where you want to render the HTML markup directly within a PHP script or template.
  • AngularJS Module Required: crmSearchDisplay
  • How it works: It fetches the configuration settings and builds the HTML tag (e.g., <crm-search-display-table>) with the settings prepopulated as attributes.

Example (PHP):

$result = \Civi\Api4\SearchDisplay::getMarkup(FALSE)
  ->addWhere('id', '=', $searchDisplayId)
  ->addFilter('first_name', 'Sue')
  ->execute()->first();

$markup = $result['markup'];
// $markup contains:
// <crm-search-display-table search="'my_saved_search'" display="'my_display'" api-entity="Individual" settings="..." filters="{first_name: 'Sue'}"></crm-search-display-table>

3. Using the <crm-search-display> Directive

You can directly place the generic <crm-search-display> AngularJS component tag in your template.

  • Use case: Preferable when writing AngularJS templates or HTML pages where you want the client to dynamically fetch the configuration.
  • AngularJS Module Required: crmSearchDisplay
  • How it works: If you do not pass the configuration settings explicitly, this tag will automatically query the backend using APIv4 to fetch the required configuration data for the search display.

Example (HTML):

<crm-search-display
  search="'my_saved_search'"
  display="'my_display'"
  filters="{first_name: 'Sue'}"
></crm-search-display>
Note: Because search, display, and filters use AngularJS one-way data-bindings (<), literal strings must be enclosed in single quotes.

Ensuring AngularJS Modules are Loaded

Depending on your integration point, you must ensure that the appropriate AngularJS module is loaded (per the "AngularJS Module Required" section above):

  • From within another AngularJS module: Add the required module as a dependency in your module's declaration. For example, in an extension's .ang.php file:

    return [
      'js' => ['ang/myModule.js'],
      'requires' => ['crmSearchDisplay'],
    ];
    

  • From PHP (e.g., a Page, Form, or Hook Callback): Inject the module dynamically using the AngularJS loader service:

    \Civi::service('angularjs.loader')->addModules('crmSearchDisplay');
    // Or for an Afform module:
    \Civi::service('angularjs.loader')->addModules('myAfformModuleName');