Skip to content
RTL Support: Partial
Accessibility: Work in progress
Translations: Full
Migration Guide: Work in progress

Advance Filter

A query builder for composing nested filter rules — groups of conditions joined by AND / OR — over a set of columns. You define the filterable columns with columnOptions and bind the current query to data with v-model:data.

Each column declares a columnType (string, number, date, or select), which decides the operators and value editor offered for that column — text operators for string, comparisons for number, date pickers for date, and so on. The examples below are grouped by column type; each shows the default operators for that type alongside a customized set supplied through operatorOptions.

See here on how to use it inside a table.

Basic Usage

vue
<script setup lang="ts">
  import { h, ref } from 'vue'
  import { HLAdvanceFilter, HLIcon } from '@platform-ui/highrise'
  import { CalendarIcon, Phone01Icon } from '@gohighlevel/ghl-icons/24/outline'

  const defaultOptions = [
    { label: 'First Name', value: 'first_name', columnType: 'string' },
    {
      label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, Phone01Icon), 'Phone']),
      value: 'phone',
      columnType: 'string',
    },
    { label: 'Age', value: 'age', columnType: 'number' },
    {
      label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, CalendarIcon), 'Birthday']),
      value: 'birthday',
      columnType: 'date',
    },
  ]

  const defaultData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'first_name', // value of the option in the columnOptions
            operator: 'contains', // operator -> based on the columnType
            value: 'ABC', // value -> based on the columnType
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="defaultOptions" v-model:data="defaultData" />
</template>

Number Column

Default Usage

Customized Usage

vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const numberColumn = [{ label: 'Age', value: 'age', columnType: 'number' }]
  const numberData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'age',
            operator: 'less_or_equal',
            value: 18,
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="numberColumn" v-model:data="numberData" />
</template>
vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const numberCustomizedColumn = [
    {
      label: 'Age',
      value: 'age',
      columnType: 'number',
      operatorOptions: [
        {
          label: 'Is less than',
          value: 'less',
          valueType: 'number',
          props: { min: 10, max: 20 },
        },
        {
          label: 'Is greater than',
          value: 'greater',
          valueType: 'number',
          props: { min: 10, max: 20 },
        },
      ],
    },
  ]
  const numberCustomizedData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'age',
            operator: 'less',
            value: 18,
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="numberCustomizedColumn" v-model:data="numberCustomizedData" />
</template>

String Column

Default Usage

Customized Usage

vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const stringColumn = [{ label: 'First Name', value: 'first_name', columnType: 'string' }]
  const stringData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'first_name',
            operator: 'equal',
            value: 'John',
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="stringColumn" v-model:data="stringData" />
</template>
vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const stringCustomizedColumn = [
    {
      label: 'First Name',
      value: 'first_name',
      columnType: 'string',
      operatorOptions: [
        {
          label: 'Is equal to',
          value: 'equal',
          valueType: 'string',
        },
        {
          label: 'Is not equal to',
          value: 'not_equal',
          valueType: 'string',
        },
      ],
    },
  ]
  const stringCustomizedData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'first_name',
            operator: 'equal',
            value: 'John',
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="stringCustomizedColumn" v-model:data="stringCustomizedData" />
</template>

Date Column

Default Usage

Customized Usage

vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const dateColumn = [{ label: 'Birthday', value: 'birthday', columnType: 'date' }]
  const dateData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'birthday',
            operator: 'greater',
            value: 1762799400000,
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="dateColumn" v-model:data="dateData" />
</template>
vue
<script setup lang="ts">
  import { ref } from 'vue'
  import { HLAdvanceFilter } from '@platform-ui/highrise'

  const dateCustomizedColumn = [
    {
      label: 'Birthday',
      value: 'birthday',
      columnType: 'date',
      operatorOptions: [
        {
          label: 'Is greater than',
          value: 'greater',
          valueType: 'date',
        },
        {
          label: 'Is less than',
          value: 'less',
          valueType: 'date',
        },
      ],
    },
  ]
  const dateCustomizedData = ref({
    condition: 'OR',
    rules: [
      {
        condition: 'AND',
        rules: [
          {
            field: 'birthday',
            operator: 'greater',
            value: 1762799400000,
          },
        ],
      },
    ],
  })
</script>
<template>
  <HLAdvanceFilter :columnOptions="dateCustomizedColumn" v-model:data="dateCustomizedData" />
</template>

Mixed Filter Column

O1

Option 1

O2

Option 2
ANDOR
vue
<script setup lang="ts">
import { ref } from 'vue'
import { HLAdvanceFilter } from '@platform-ui/highrise'

const mixedFilterColumn = [
  {
    label: 'Custom Select',
    value: 'custom_select',
    columnType: 'select',
    operatorOptions: [
      {
        type: 'group',
        label: 'Filter by value',
        key: 'Filter by value',
        children: [
          {
            label: 'In',
            value: 'in',
            valueType: 'select',
            props: {
              multiple: true,
              options: [
                { label: 'Option 1', value: 'option1' },
                { label: 'Option 2', value: 'option2' },
                { label: 'Option 3', value: 'option3' },
              ],
            },
          },
        ],
      },
      {
        type: 'group',
        label: 'Filter by Condition',
        key: 'Filter by Condition',
        children: [
          {
            label: 'greater than',
            value: 'greater_than',
            valueType: 'number',
            props: { min: 10, max: 20 },
          },
          {
            label: 'Is between',
            value: 'between',
            valueType: 'numberRange',
            props: { min: 10, max: 20, showInput: true },
          },
        ],
      },
    ],
  },
]
const mixedFilterData = ref({
  condition: 'OR',
  rules: [
    {
      condition: 'OR',
      rules: [
        {
          field: 'custom_select',
          operator: 'in',
          value: ['option1', 'option2'],
        },
        {
          field: 'custom_select',
          operator: 'greater_than',
          value: 10,
        },
      ],
    },
  ],
})
</script>
<template>
  <HLAdvanceFilter :columnOptions="mixedFilterColumn" v-model:data="mixedFilterData" />
</template>

Customized Usage

ANDOR
ANDOR
ANDOR
vue
<script setup lang="ts">
import { h, ref } from 'vue'
import { HLAdvanceFilter, HLIcon } from '@platform-ui/highrise'
import { CalendarIcon, ImageUserIcon, Mail01Icon, Phone01Icon } from '@gohighlevel/ghl-icons/24/outline'

const customColumnOptions = [
  {
    label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, ImageUserIcon), 'Name']),
    value: 'name',
    columnType: 'string',
  },
  {
    label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, Mail01Icon), 'Email']),
    value: 'email',
    columnType: 'string',
  },
  {
    label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, Phone01Icon), 'Phone']),
    value: 'phone',
    columnType: 'string',
  },
  {
    label: 'Rating',
    value: 'rating',
    columnType: 'select',
    operatorOptions: [
      {
        type: 'group',
        label: 'Filter by value',
        key: 'Filter by value',
        children: [
          {
            label: 'In',
            value: 'in',
            valueType: 'select',
            props: {
              multiple: true,
              options: [
                { label: 'Option 1', value: 'option1' },
                { label: 'Option 2', value: 'option2' },
                { label: 'Option 3', value: 'option3' },
              ],
            },
          },
        ],
      },
      {
        type: 'group',
        label: 'Filter by Condition',
        key: 'Filter by Condition',
        children: [
          {
            label: 'greater than',
            value: 'greater_than',
            valueType: 'number',
            props: { min: 10, max: 20 },
          },
          {
            label: 'less than',
            value: 'less_than',
            valueType: 'number',
            props: { min: 10, max: 20 },
          },
        ],
      },
    ],
  },
  {
    label: 'Age',
    value: 'age',
    columnType: 'number',
    operatorOptions: [
      {
        label: 'Is less than or equal to',
        value: 'less_or_equal',
        valueType: 'number',
        props: { min: 10, max: 20 },
      },
      {
        label: 'Is between',
        value: 'between',
        valueType: 'numberRange',
        props: { min: 10, max: 20, showInput: true },
      },
    ],
  },
  {
    label: h('div', { class: 'flex items-center gap-1' }, [h(HLIcon, { size: 14 }, CalendarIcon), 'Birthday']),
    value: 'birthday',
    columnType: 'date',
  },
  {
    label: 'Custom Select',
    value: 'custom_select',
    columnType: 'select',
    operatorOptions: [
      {
        label: 'Select In',
        value: 'select_in',
        valueType: 'select',
        props: {
          multiple: true,
          options: [
            { label: 'Option 1', value: 'option1' },
            { label: 'Option 2', value: 'option2' },
            { label: 'Option 3', value: 'option3' },
          ],
        },
      },
      { label: 'Number Selection', value: 'not_null', valueType: 'number' },
    ],
  },
]

const customData = ref({
  condition: 'AND',
  rules: [
    {
      condition: 'OR',
      rules: [
        {
          field: 'name',
          operator: 'equal',
          value: 'Mara',
        },
        {
          field: 'age',
          operator: 'less_or_equal',
          value: 18,
        },
      ],
    },
    {
      condition: 'OR',
      rules: [
        {
          field: 'birthday',
          operator: 'greater',
          value: 1762799400000,
        },
        {
          field: 'age',
          operator: 'equal',
          value: 20,
        },
      ],
    },
  ],
})
</script>
<template>
  <HLAdvanceFilter :columnOptions="customColumnOptions" v-model:data="customData" />
</template>

Live Demo

{
  "condition": "OR",
  "rules": [
    {
      "condition": "AND",
      "rules": [
        {
          "field": "first_name",
          "operator": "contains",
          "value": "ABC"
        }
      ]
    }
  ]
}
    

Props

PropTypeDefaultDescription
columnOptionsHLAdvanceFilterColumnOption[]-The columns to display in the filter
dataHLAdvanceFilterData-The data to display in the filter
selectColumnPropsObject see here-The props to pass to the select field column

Types

ts
import type { VNode } from 'vue'

interface HLAdvanceFilterColumnOption {
  // Column label shown in the field dropdown. A plain string, or a VNode
  // (e.g. `h('div', [h(HLIcon, ...), 'Phone'])`) to render an icon beside the text.
  label: string | VNode
  value: string
  columnType: 'string' | 'number' | 'date' | 'select'
  operatorOptions?: OperatorOption[]
  operatorProps?: Object
}

interface OperatorOption {
  props?: Object
  label?: string
  key?: string
  children?: OperatorOption[]
  type?: 'group' | 'option'
  value?: string
  valueType?: 'string' | 'number' | 'date' | 'select' | 'numberRange' | 'dateRange'
}
ts
interface HLAdvanceFilterData {
  condition: 'AND' | 'OR'
  rules: {
    condition: 'AND' | 'OR'
    rules: {
      field: string | null
      operator: Operator | null
      // string | number | boolean | null | number[]
      value: string | number | boolean | null | number[]
    }[]
  }[]
}

// Built-in operator keys. Also accepts any custom string you define
// via a column's `operatorOptions[].value`.
type Operator =
  | 'equal'
  | 'not_equal'
  | 'greater'
  | 'greater_or_equal'
  | 'less'
  | 'less_or_equal'
  | 'in'
  | 'not_in'
  | 'between'
  | 'not_between'
  | 'contains'
  | 'not_contains'
  | 'begins_with'
  | 'ends_with'
  | 'is_not_empty'
  | 'is_null'
  | 'is_not_null'
  | 'is_empty'
  | 'is_true'
  | 'is_false'
  | string
ts
const defaultOperatorOptions = {
  number: [
    { label: 'Is equals to', value: 'equal', valueType: 'number' },
    { label: 'Is not equals to', value: 'not_equal', valueType: 'number' },
    { label: 'Is greater than', value: 'greater', valueType: 'number' },
    { label: 'Is greater than or equal to', value: 'greater_or_equal', valueType: 'number' },
    { label: 'Is less than', value: 'less', valueType: 'number' },
    { label: 'Is less than or equal to', value: 'less_or_equal', valueType: 'number' },
    { label: 'Is between', value: 'between', valueType: 'numberRange' },
    { label: 'Is not between', value: 'not_between', valueType: 'numberRange' },
  ],
  string: [
    { label: 'Text Contains', value: 'contains', valueType: 'string' },
    { label: 'Text Does Not Contain', value: 'not_contains', valueType: 'string' },
    { label: 'Text Starts With', value: 'begins_with', valueType: 'string' },
    { label: 'Text Ends With', value: 'ends_with', valueType: 'string' },
    { label: 'Text is Exactly', value: 'equal', valueType: 'string' },
  ],
  date: [
    { label: 'Date is before', value: 'less', valueType: 'date' },
    { label: 'Date is after', value: 'greater', valueType: 'date' },
    { label: 'Date is', value: 'equal', valueType: 'date' },
    { label: 'Date is between', value: 'between', valueType: 'dateRange' },
    { label: 'Date is not between', value: 'not_between', valueType: 'dateRange' },
  ],
}

Emits

EventParametersDescription
update:data(data: HLAdvanceFilterData) => voidEmitted when the data changes

Methods

MethodParametersDescription
setFilterData(data: HLAdvanceFilterData)Sets the filter data