Date Filter with Preset Ranges

When building a date filtering UI a date range picker is essential. On top of being able to select custom start and end dates presets can be very helpful and provide a nice productivity boost. A more advanced filtering experience can be created in a couple of steps:

  • Custom popup with an inline calendar - Create a custom popup and place an inline date picker with start/end selection
  • Select with common presets - Populate a dropdown with values like Today, Yesterday, Last week, Last month, Last 7 days, Last 30 days
  • Inputs for typing dates - Adding two inputs next to the range picker enables users to type in a date rather than solely relying on manual selection
  • Make it fully responsive - Use the responsive api to customize the desktop experience - dropdown with inputs for typing - and the mobile experience - touch optimized interface
Get started with this example

Demo

Loading the live demo

Preview in full screen

Code

<script setup>
import {
  formatDate,
  MbscButton,
  MbscDatepicker,
  MbscInput,
  MbscPage,
  MbscPopup,
  MbscSelect,
  options,
  setOptions 
} from '@mobiscroll/vue'
import { onMounted, ref } from 'vue'

setOptions({
  locale:  ,
  theme: ' ',
  themeVariant: ' '
})

const now = new Date()
const day = now.getDay()
const monday = now.getDate() - day + (day === 0 ? -6 : 1)
const startDate = '2026-11-01T00:00'
const endDate = '2026-11-07T00:00'

const startInput = ref(null)
const endInput = ref(null)
const dateInput = ref('')
const selected = ref('custom')
const selectedDate = ref([startDate, endDate])
const disableInput = ref(false)
const isPopupOpen = ref(false)

const respPopup = {
  responsive: {
    xsmall: {
      display: 'bottom',
      touchUi: true,
      buttons: [
        {
          text: 'Apply',
          handler: () => {
            const date = selectedDate.value

            changeInputValue(date[0], date[1] || date[0])
            isPopupOpen.value = true
          }
        },
        'cancel'
      ]
    },
    custom: {
      breakpoint: 559,
      buttons: [],
      display: 'anchored',
      anchor: document.querySelector('.date-filter-input'),
      anchorAlign: 'start',
      touchUi: false,
      scrollLock: false,
      showArrow: false,
      maxWidth: 920
    }
  }
}

const respSelect = {
  xsmall: {
    touchUi: true
  },
  small: {
    touchUi: false
  }
}

const myData = [
  {
    value: 'custom',
    text: 'Custom'
  },
  {
    value: 'today',
    text: 'Today'
  },
  {
    value: 'yesterday',
    text: 'Yesterday'
  },
  {
    value: 'last-week',
    text: 'Last week'
  },
  {
    value: 'last-month',
    text: 'Last month'
  },
  {
    value: 'last-7-days',
    text: 'Last 7 days'
  },
  {
    value: 'last-30-days',
    text: 'Last 30 days'
  }
]

function handleSelectChange(event) {
  const s = event.value

  if (s === 'custom') {
    disableInput.value = false
  } else {
    disableInput.value = true

    switch (s) {
      case 'today':
        selectedDate.value = ['2021-09-15T00:00', '2021-09-15T00:00']
        break
      case 'yesterday':
        selectedDate.value = ['2021-09-14T00:00', '2021-09-14T00:00']
        break
      case 'last-week':
        selectedDate.value = [
          new Date(now.getFullYear(), now.getMonth(), monday - 7),
          new Date(now.getFullYear(), now.getMonth(), monday - 1)
        ]
        break
      case 'last-month':
        selectedDate.value = ['2021-08-01T00:00', '2021-08-31T00:00']
        break
      case 'last-7-days':
        selectedDate.value = ['2021-09-09T00:00', '2021-09-15T00:00']
        break
      case 'last-30-days':
        selectedDate.value = ['2021-08-17T00:00', '2021-09-15T00:00']
        break
      default:
        break
    }
  }
  selected.value = s
}

function handleCalendarChange() {
  disableInput.value = false
}

function handleInputClick() {
  isPopupOpen.value = true
}

function changeInputValue(start, end) {
  const locale = options.locale || {}
  const dateFormat = locale.dateFormat || 'DD/MM/YYYY'

  dateInput.value =
    formatDate(dateFormat, new Date(start)) + ' - ' + formatDate(dateFormat, new Date(end))
}

function applyClick() {
  const date = selectedDate.value

  changeInputValue(date[0], date[1] || date[0])
  isPopupOpen.value = false
}

function cancelClick() {
  isPopupOpen.value = false
}

function handlePopupClose() {
  isPopupOpen.value = false
}

onMounted(() => {
  changeInputValue(startDate, endDate)
})
</script>

<template>
  <MbscPage>
    <div class="mbsc-form-group">
      <MbscInput
        v-model="dateInput"
        inputStyle="box"
        labelStyle="stacked"
        @click="handleInputClick"
      />
    </div>
    <MbscPopup
      className="demo-date-filtering-popup"
      :responsive="respPopup"
      :isOpen="isPopupOpen"
      @close="handlePopupClose"
    >
      <div class="mbsc-grid mbsc-no-padding">
        <div class="mbsc-row">
          <div class="mbsc-col-sm-4 mbsc-push-sm-8 demo-date-filtering-dates">
            <div class="demo-date-filtering-inputs">
              <MbscSelect
                v-model="selected"
                :data="myData"
                :responsive="respSelect"
                label="Date range"
                inputStyle="box"
                labelStyle="stacked"
                @change="handleSelectChange"
              />
              <MbscInput
                ref="startInput"
                label="Start"
                inputStyle="box"
                labelStyle="stacked"
                :disabled="disableInput"
              />
              <MbscInput
                ref="endInput"
                label="End"
                inputStyle="box"
                labelStyle="stacked"
                :disabled="disableInput"
              />
            </div>
            <div class="demo-date-filtering-desktop-buttons mbsc-button-group-justified">
              <MbscButton className="apply-button" @click="applyClick">Apply</MbscButton>
              <MbscButton className="cancel-button" @click="cancelClick">Cancel</MbscButton>
            </div>
          </div>
          <div class="mbsc-col-sm-8 mbsc-pull-sm-4">
            <MbscDatepicker
              v-model="selectedDate"
              select="range"
              display="inline"
              pages="auto"
              returnFormat="iso8601"
              :startInput="startInput"
              :endInput="endInput"
              :controls="['calendar']"
              :showRangeLabels="false"
              :showOnClick="false"
              :showOnFocus="false"
              @change="handleCalendarChange"
            />
          </div>
        </div>
      </div>
    </MbscPopup>
  </MbscPage>
</template>

<style>
.demo-date-filtering-popup .mbsc-ios.mbsc-datepicker-inline {
  border: none;
  border-radius: 4px;
  overflow: hidden;
}

.demo-date-filtering-popup .mbsc-textfield-wrapper-box {
  margin-top: 0;
  margin-right: 0;
}

.demo-date-filtering-dates {
  display: flex;
  flex-direction: column;
}

.demo-date-filtering-inputs {
  flex: 1;
}

.demo-date-filtering-desktop-buttons.mbsc-button-group-justified,
.demo-date-filtering-desktop-buttons.mbsc-button-group-justified button {
  margin-bottom: 0;
}

@media (max-width: 575px) {
  .demo-date-filtering-desktop-buttons {
    display: none;
  }
  .demo-date-filtering-popup .mbsc-textfield-wrapper-box {
    margin-left: 0;
  }
}
</style>

Duplicate Session

You have signed in on a different machine. To keep everything in sync, you have been signed out of this session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.

Duplicate Session

We noticed you are logged in on a different machine and have closed your old session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.