Custom Dashboard Filters

It is possible to register a custom filter and use it as a DisplayFilter for Dashboards or search modals.

At the moment there are 2 types of custom filters

Hint: If you want to create a filter with metadata, make sure they are setup correctly in the ElasticSearch index (search.metadata_mapping config in the server)

Custom List v2 Filter

Example Single Value Filter

searchFilters.registerListV2 registers an object where you can configure a filter object which is used to render the search UI.

Filter Dropdown


  • datasource.fetch fetch data async from a remote service or create a list of filter items
  • mount - configure the filter object
liEditor.searchFilters.registerListV2('contentTypeV2Filter', {
  datasource: {
    // fetch data and inject response into mount function
    async fetch ({project, user, server, config}) {
      const host =
      const channelId =
      const uri = `${host}/channel-configs/properties?channelId=${channelId}&properties=contentTypes`

      const response = await window.fetch(uri, {
        method: 'GET',
        headers: new window.Headers({
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${server.accessToken}`

      // only succeed on status codes 200 - 299
      if (!response.ok) throw new Error('contentTypeV2Filter was not able to fetch data')
      return response.json()

  // Mount a search filter (search behaviour, display options)
  // @param data injected result from datasource.fetch
  // @example options = [
  //   {
  //     label: 'Regular Article',
  //     filter: {key: 'contentType', term: 'regular'}
  //   },
  //   {
  //     label: 'Page',
  //     filter: {key: 'contentType', term: 'page'},
  //     isDefault: true
  //   }
  // ]
  async mount ({data, filter}) {
    const options = => {
      return {
        // these props are used for creating a search request (see 'Filter Query Types' link below)
        filter: {key: 'contentType', term: ct.handle}
    filter.options = options

Hint: Look into Filter Query Types to find possible {type, value} combinations for the filter.options in the mount function.

Example Multi Value Filter

image Filter Dropdown

liEditor.searchFilters.registerListV2('MultiSelectV2Filter', {
  multiple: true, // allow multiple selections
  label: {en: 'Multi Select', de: 'Mehrfachauswahl'},
  datasource: {
    fetch ({user}) {
      return [{
        label: {en: 'Published Articles', de: 'Publizierte Artikel'},
        filter: {key: 'lastPublicationId', exists: true}
        label: {en: 'My Articles', de: 'Meine Artikel'},
        filter: {key: 'ownerId', term:}

  mount ({data, filter}) {
    filter.options = data

The selected values are OR combined in the search query.

Request payload if both filters from above are selected:

  { "or": [
    { "key": "lastPublicationId", "exists": true },
    { "key": "ownerId", "term":1 }
isDefault option

When isDefault: true (see example above), the default option will be added to the search query by default. As soon as one selects a filter manually, the default filter option will be ignored.

Custom Vue Component Filter

Filters for the media-library need to define the dataType

// before release-2023-07
$emit('update:filter', {type: 'metadata', key:'transformed', dataType: 'boolean', value: true})

// after release-2023-07, uses the new Search DSL
$emit('update:filter', {filter: {key:'metadata.transformed', term: true}})

vueComponentRegistry.registerComponent({type: 'searchFilter'}) registers a Vue component as filter for the search UI. Below you can see a minimal example:

  type: 'searchFilter',
  name: 'customFilter',
  component: require('./filters/custom-filter.vue').default

After registering the filter, the vue component will recieve a prop called filter and the upstream-editor has some logic behind the scenes. For example the filter is written onto the localStorage so it persists through refreshing or navigating and triggers the search, or is cleared after resetting the filter settings.

  <!-- the 'update:filter' event is required -->
    @click="$emit('update:filter', {filter: {key: 'updatedAt', range: {gte: 'now-24h'}})">
  Filter logic

<style lang="scss" scoped>
  .my-css-class {

export default {
  name: 'customFilter',
  // synced with it's parent and the value in the localStorage
  // updated via $emit('update:filter', {})
  props: {
    filter: {
      type: Object,
      default () {}