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 4 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)

Register Custom List v2 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 = [{
  //     id: 'regular',
  //     label: 'Regular Article',
  //     type: 'contentType',
  //     value: 'regular'
  //   }, {
  //     id: 'page',
  //     label: 'Page',
  //     type: 'contentType',
  //     value: 'page',
  //     isDefault: true
  //   }]
  async mount ({data, filter}) {
    const options = => {
      return {
        id: ct.handle,
        // these props are used for creating a search request (see 'Filter Query Types' link below)
        type: 'contentType',
        value: 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.

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.

Register Custom List Filter

Deprecated since: release-2020-02


searchFilters.registerList registers a filter based on a config object to create an Angular directive for the search UI. Display is controlled with the filters key in the configuration.

There are two flavors to this function

liEditor.searchFilters.registerList('creation-date', ['session', 'config', (session, config) => {
  const channels = _map(session.project.channels, (channel) => ({
    label: channel.label,
    // type and value are used in the query builder
    type: 'channelId',

  return {
    title: 'Filter by channels',
    options: channels

liEditor.searchFilters.registerList('creationDate', {
  title: 'Filter by creation date',
  options: [{
    id: '2015',
    label: 'Created in 2015',
    type: 'dateRange',
    key: 'created_at',
    from: new Date('2015-01-01'),
    to: new Date('2016-01-01')
  }, {
    id: '2016',
    label: 'Created in 2016',
    type: 'dateRange',
    key: 'created_at',
    from: new Date('2016-01-01'),
    to: new Date('2017-01-01'),
    isDefault: true

Register Custom Vue Component Filter

release-2021-03 Filters for the media-library need to define the dataType

$emit('update:filter', {type: 'metadata', key:'transformed', dataType: 'boolean', value: 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', {type: 'dateRange', amount: 24, value: 'h'})">
  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 () {}

Register Custom Angular Component Filter


searchFilters.registerAngularComponent registers an Angular component as filter for the search UI. Display is controlled with the filters key in the configuration.

liEditor.searchFilters.registerAngularComponent('test', {
  bindings: {
    value: '=',
    config: '='
  template: `
      ng-class="{'is-set': $ctrl.isActive}"
      <div class="ld-dropdown__text">
        Show print documents
  controller: class PrintController {
    static get $inject () { return ['session'] }

    constructor (session) {
      this.session = session = _find(session.project.channels, {handle: 'print'}) || {}
      this.hasPrint = !!

    $doCheck () {
      this.isActive = this.value.get()

    toggleProjectFilter () {
      if ( this.isActive = !this.isActive
      if (this.isActive && {
        this.value.set({type: 'channelId', value:})
      } else {