Skip to content

Variable: RDateField

ts
const RDateField: DefineComponent<ExtractPropTypes<AppendDefault<{
  active: BooleanConstructor;
  allowUnspecifiedChoices: {
     default: boolean;
     type: BooleanConstructor;
  };
  autocomplete: PropType<string>;
  autofocus: BooleanConstructor;
  baseColor: StringConstructor;
  bgColor: StringConstructor;
  choices: {
     default: undefined;
     type: PropType<any[] | undefined>;
  };
  class: PropType<any>;
  clearable: BooleanConstructor;
  clearIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
      }>;
     type: PropType<
        | IconValue
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
     }>>;
  };
  color: StringConstructor;
  datePickerIcon: {
     default: () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
     }>;
     type: PropType<IconValue>;
  };
  density: {
     default: string;
     type: PropType<Density>;
     validator: (v: any) => boolean;
  };
  direction: {
     default: string;
     type: PropType<"vertical" | "horizontal">;
     validator: (v: any) => boolean;
  };
  dirty: BooleanConstructor;
  disabled: {
     default: null;
     type: BooleanConstructor;
  };
  displayFormat: {
     default: string;
     type: PropType<"short" | "med" | "medWithWeekday" | "full" | "huge">;
  };
  displayLocale: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  displayTimezone: {
     default: undefined;
     type: PropType<string | Zone<boolean> | undefined>;
  };
  error: BooleanConstructor;
  errorMessages: {
     default: () => never[];
     type: PropType<string | readonly string[] | null>;
  };
  firstDayOfWeek: {
     default: undefined;
     type: (NumberConstructor | StringConstructor)[];
  };
  flat: BooleanConstructor;
  focused: BooleanConstructor;
  glow: BooleanConstructor;
  hideDetails: PropType<boolean | "auto">;
  hint: StringConstructor;
  href: StringConstructor;
  iconColor: (StringConstructor | BooleanConstructor)[];
  id: StringConstructor;
  label: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  loading: (StringConstructor | BooleanConstructor)[];
  max: PropType<unknown>;
  maxErrors: {
     default: number;
     type: (NumberConstructor | StringConstructor)[];
  };
  maxWidth: (NumberConstructor | StringConstructor)[];
  menuIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
      }>;
     type: PropType<
        | IconValue
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
     }>>;
  };
  messages: {
     default: () => never[];
     type: PropType<string | readonly string[]>;
  };
  min: PropType<unknown>;
  minWidth: (NumberConstructor | StringConstructor)[];
  modeIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
      }>;
     type: PropType<
        | IconValue
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
     }>>;
  };
  modelValue: {
     default: undefined;
     type: PropType<string | string[] | null | undefined>;
  };
  multiple: {
     default: boolean;
     type: PropType<boolean>;
  };
  name: StringConstructor;
  nextIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
      }>;
     type: PropType<
        | IconValue
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
     }>>;
  };
  noValuesText: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  onBlur: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onChange: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onClick:append?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:appendInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:clear?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:prepend?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:prependInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onInput: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onMousedown:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onUpdate:focused?: PropType<(...args: [boolean]) => void | undefined>;
  onUpdate:model-value?: PropType<(...args: [string | ...[] | null]) => void | undefined>;
  onUpdate:modelValue?: PropType<(...args: [string | ...[] | null]) => void | undefined>;
  persistentClear: BooleanConstructor;
  persistentHint: BooleanConstructor;
  persistentPlaceholder: BooleanConstructor;
  placeholder: StringConstructor;
  prefix: StringConstructor;
  prevIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
      }>;
     type: PropType<
        | IconValue
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
     }>>;
  };
  readonly: {
     default: null;
     type: PropType<boolean | null>;
  };
  renderMode: {
     default: string;
     type: PropType<"edit" | "read">;
  };
  reverse: BooleanConstructor;
  role: {
     default: string;
     type: PropType<string>;
  };
  rounded: {
     default: undefined;
     type: (NumberConstructor | StringConstructor | BooleanConstructor)[];
  };
  showWeek: BooleanConstructor;
  singleLine: BooleanConstructor;
  style: {
     default: null;
     type: PropType<StyleValue>;
  };
  suffix: StringConstructor;
  theme: StringConstructor;
  tile: BooleanConstructor;
  to: PropType<
     | string
     | RouteLocationAsRelativeGeneric
    | RouteLocationAsPathGeneric>;
  validateOn: PropType<
     | "eager"
     | "input"
     | "blur"
     | "submit"
     | "invalid-input"
     | "input lazy"
     | "blur lazy"
     | "submit lazy"
     | "invalid-input lazy"
     | "input eager"
     | "blur eager"
     | "submit eager"
     | "invalid-input eager"
     | "lazy input"
     | "lazy blur"
     | "lazy submit"
     | "lazy invalid-input"
     | "eager input"
     | "eager blur"
     | "eager submit"
     | "eager invalid-input"
     | "lazy"
    | undefined>;
  variant: {
     default: string;
     type: PropType<
        | "outlined"
        | "plain"
        | "underlined"
        | "filled"
        | "solo"
        | "solo-inverted"
       | "solo-filled">;
     validator: (v: any) => boolean;
  };
  width: (NumberConstructor | StringConstructor)[];
}, {
}>>, () =>
  | VNode<RendererNode, RendererElement, {
[key: string]: any;
}>
  | null, {
}, {
}, {
}, ComponentOptionsMixin, ComponentOptionsMixin, EmitFunctions<{
  click:append: (...args: [MouseEvent]) => boolean;
  click:appendInner: (...args: [MouseEvent]) => boolean;
  click:clear: (...args: [MouseEvent]) => boolean;
  click:control: (...args: [MouseEvent]) => boolean;
  click:prepend: (...args: [MouseEvent]) => boolean;
  click:prependInner: (...args: [MouseEvent]) => boolean;
  mousedown:control: (...args: [MouseEvent]) => boolean;
  update:focused: (...args: [boolean]) => boolean;
  update:model-value: (value: string | string[] | null | undefined) => boolean;
  update:modelValue: (value: string | string[] | null | undefined) => boolean;
}>, string, PublicProps, ToResolvedProps<ExtractPropTypes<AppendDefault<{
  active: BooleanConstructor;
  allowUnspecifiedChoices: {
     default: boolean;
     type: BooleanConstructor;
  };
  autocomplete: PropType<string>;
  autofocus: BooleanConstructor;
  baseColor: StringConstructor;
  bgColor: StringConstructor;
  choices: {
     default: undefined;
     type: PropType<any[] | undefined>;
  };
  class: PropType<any>;
  clearable: BooleanConstructor;
  clearIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
      }>;
     type: PropType<
        | IconValue
       | () => VNode<..., ..., ...>>;
  };
  color: StringConstructor;
  datePickerIcon: {
     default: () => VNode<RendererNode, RendererElement, {
      [key: string]: any;
     }>;
     type: PropType<IconValue>;
  };
  density: {
     default: string;
     type: PropType<Density>;
     validator: (v: any) => boolean;
  };
  direction: {
     default: string;
     type: PropType<"vertical" | "horizontal">;
     validator: (v: any) => boolean;
  };
  dirty: BooleanConstructor;
  disabled: {
     default: null;
     type: BooleanConstructor;
  };
  displayFormat: {
     default: string;
     type: PropType<"short" | "med" | "medWithWeekday" | "full" | "huge">;
  };
  displayLocale: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  displayTimezone: {
     default: undefined;
     type: PropType<string | Zone<boolean> | undefined>;
  };
  error: BooleanConstructor;
  errorMessages: {
     default: () => never[];
     type: PropType<string | readonly string[] | null>;
  };
  firstDayOfWeek: {
     default: undefined;
     type: (NumberConstructor | StringConstructor)[];
  };
  flat: BooleanConstructor;
  focused: BooleanConstructor;
  glow: BooleanConstructor;
  hideDetails: PropType<boolean | "auto">;
  hint: StringConstructor;
  href: StringConstructor;
  iconColor: (StringConstructor | BooleanConstructor)[];
  id: StringConstructor;
  label: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  loading: (StringConstructor | BooleanConstructor)[];
  max: PropType<unknown>;
  maxErrors: {
     default: number;
     type: (NumberConstructor | StringConstructor)[];
  };
  maxWidth: (NumberConstructor | StringConstructor)[];
  menuIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
      }>;
     type: PropType<
        | IconValue
       | () => VNode<..., ..., ...>>;
  };
  messages: {
     default: () => never[];
     type: PropType<string | readonly string[]>;
  };
  min: PropType<unknown>;
  minWidth: (NumberConstructor | StringConstructor)[];
  modeIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
      }>;
     type: PropType<
        | IconValue
       | () => VNode<..., ..., ...>>;
  };
  modelValue: {
     default: undefined;
     type: PropType<string | string[] | null | undefined>;
  };
  multiple: {
     default: boolean;
     type: PropType<boolean>;
  };
  name: StringConstructor;
  nextIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
      }>;
     type: PropType<
        | IconValue
       | () => VNode<..., ..., ...>>;
  };
  noValuesText: {
     default: undefined;
     type: PropType<string | undefined>;
  };
  onBlur: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onChange: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onClick:append?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:appendInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:clear?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:prepend?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onClick:prependInner?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onInput: {
     default: undefined;
     type: PropType<() => void | undefined>;
  };
  onMousedown:control?: PropType<(...args: [MouseEvent]) => void | undefined>;
  onUpdate:focused?: PropType<(...args: [boolean]) => void | undefined>;
  onUpdate:model-value?: PropType<(...args: [... | ... | ... | ...]) => void | undefined>;
  onUpdate:modelValue?: PropType<(...args: [... | ... | ... | ...]) => void | undefined>;
  persistentClear: BooleanConstructor;
  persistentHint: BooleanConstructor;
  persistentPlaceholder: BooleanConstructor;
  placeholder: StringConstructor;
  prefix: StringConstructor;
  prevIcon: Omit<{
     default: string;
     type: PropType<IconValue>;
   }, "type" | "default"> & {
     default:   | NonNullable<IconValue>
        | () => VNode<RendererNode, RendererElement, {
      [key: ...]: ...;
      }>;
     type: PropType<
        | IconValue
       | () => VNode<..., ..., ...>>;
  };
  readonly: {
     default: null;
     type: PropType<boolean | null>;
  };
  renderMode: {
     default: string;
     type: PropType<"edit" | "read">;
  };
  reverse: BooleanConstructor;
  role: {
     default: string;
     type: PropType<string>;
  };
  rounded: {
     default: undefined;
     type: (NumberConstructor | StringConstructor | BooleanConstructor)[];
  };
  showWeek: BooleanConstructor;
  singleLine: BooleanConstructor;
  style: {
     default: null;
     type: PropType<StyleValue>;
  };
  suffix: StringConstructor;
  theme: StringConstructor;
  tile: BooleanConstructor;
  to: PropType<
     | string
     | RouteLocationAsRelativeGeneric
    | RouteLocationAsPathGeneric>;
  validateOn: PropType<
     | "eager"
     | "input"
     | "blur"
     | "submit"
     | "invalid-input"
     | "input lazy"
     | "blur lazy"
     | "submit lazy"
     | "invalid-input lazy"
     | "input eager"
     | "blur eager"
     | "submit eager"
     | "invalid-input eager"
     | "lazy input"
     | "lazy blur"
     | "lazy submit"
     | "lazy invalid-input"
     | "eager input"
     | "eager blur"
     | "eager submit"
     | "eager invalid-input"
     | "lazy"
    | undefined>;
  variant: {
     default: string;
     type: PropType<
        | "outlined"
        | "plain"
        | "underlined"
        | "filled"
        | "solo"
        | "solo-inverted"
       | "solo-filled">;
     validator: (v: any) => boolean;
  };
  width: (NumberConstructor | StringConstructor)[];
}, {
}>>, EmitFunctions<{
  click:append: (...args: [MouseEvent]) => boolean;
  click:appendInner: (...args: [MouseEvent]) => boolean;
  click:clear: (...args: [MouseEvent]) => boolean;
  click:control: (...args: [MouseEvent]) => boolean;
  click:prepend: (...args: [MouseEvent]) => boolean;
  click:prependInner: (...args: [MouseEvent]) => boolean;
  mousedown:control: (...args: [MouseEvent]) => boolean;
  update:focused: (...args: [boolean]) => boolean;
  update:model-value: (value: string | string[] | null | undefined) => boolean;
  update:modelValue: (value: string | string[] | null | undefined) => boolean;
}>>, {
  active: boolean;
  allowUnspecifiedChoices: boolean;
  autofocus: boolean;
  choices: any[] | undefined;
  clearable: boolean;
  clearIcon:   | IconValue
     | () => VNode<RendererNode, RendererElement, {
   [key: string]: any;
   }>;
  datePickerIcon: IconValue;
  density: Density;
  direction: "vertical" | "horizontal";
  dirty: boolean;
  disabled: boolean;
  displayFormat: "short" | "med" | "medWithWeekday" | "full" | "huge";
  displayLocale: string | undefined;
  displayTimezone: string | Zone<boolean> | undefined;
  error: boolean;
  errorMessages: string | readonly string[] | null;
  firstDayOfWeek: string | number;
  flat: boolean;
  focused: boolean;
  glow: boolean;
  label: string | undefined;
  maxErrors: string | number;
  menuIcon:   | IconValue
     | () => VNode<RendererNode, RendererElement, {
   [key: string]: any;
   }>;
  messages: string | readonly string[];
  modeIcon:   | IconValue
     | () => VNode<RendererNode, RendererElement, {
   [key: string]: any;
   }>;
  modelValue: string | string[] | null | undefined;
  multiple: boolean;
  nextIcon:   | IconValue
     | () => VNode<RendererNode, RendererElement, {
   [key: string]: any;
   }>;
  noValuesText: string | undefined;
  onBlur: () => void | undefined;
  onChange: () => void | undefined;
  onInput: () => void | undefined;
  persistentClear: boolean;
  persistentHint: boolean;
  persistentPlaceholder: boolean;
  prevIcon:   | IconValue
     | () => VNode<RendererNode, RendererElement, {
   [key: string]: any;
   }>;
  readonly: boolean | null;
  renderMode: "edit" | "read";
  reverse: boolean;
  role: string;
  rounded: string | number | boolean;
  showWeek: boolean;
  singleLine: boolean;
  style: StyleValue;
  tile: boolean;
  variant:   | "outlined"
     | "plain"
     | "underlined"
     | "filled"
     | "solo"
     | "solo-inverted"
     | "solo-filled";
}, SlotsType<Partial<{
  append: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  append-inner: (arg: DefaultInputSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  clear: (arg: DefaultInputSlot & {
     props: Record<string, any>;
   }) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  counter: (arg: VCounterSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  default: (arg: {
     id: Readonly<Ref<string, string>>;
   }) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  details: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  label: (arg: DefaultInputSlot & {
     label: string | undefined;
     props: Record<string, any>;
   }) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  loader: (arg: LoaderSlotProps) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  message: (arg: VMessageSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  prepend: (arg: VInputSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
  prepend-inner: (arg: DefaultInputSlot) => VNode<RendererNode, RendererElement, {
   [key: string]: any;
  }>[];
}>>, {
}, {
}, string, ComponentProvideOptions, true, {
}, any>;

RDateField - A sophisticated Vue component for ISO 8601 date input and selection.

This component provides a comprehensive date input solution that combines the accessibility and validation benefits of HTML5 date inputs with a completely custom visual interface. It features dual input methods (manual text entry and visual picker) with intelligent mobile optimization.

Key Features

  • Dual Input Interface: Manual text entry + integrated VDatePicker
  • Mobile Optimized: VBottomSheet on mobile, VDialog on desktop
  • ISO 8601 Standard: All dates stored as YYYY-MM-DD strings
  • Luxon Formatting: Flexible display formatting with internationalization
  • Browser UI Suppression: Custom picker while preserving HTML5 benefits
  • Multiple Values: Chip-based interface for date arrays
  • Smart Readonly: Mobile inputs become readonly to prevent keyboard conflicts
  • Validation Pipeline: Ensures valid dates with midnight time components

Technical Architecture

The component uses a sophisticated multi-layer approach:

Base Layer (VTextField)

  • HTML5 type="date" for validation and mobile keyboard optimization
  • Injected CSS suppresses all native browser date picker UI
  • Maintains accessibility and semantic benefits

Picker Layer (VDatePicker)

  • Integrated via VDialog (desktop) or VBottomSheet (mobile)
  • Full calendar navigation with month/year selection
  • Configurable date constraints (min, max, firstDayOfWeek)

Mobile Layer (Touch Optimization)

  • Input becomes readonly on mobile to prevent keyboard conflicts
  • onClick:control handler directly opens picker interface
  • VBottomSheet provides optimal touch-based date selection UX

Validation Layer

  • Ensures ISO 8601 compliance (YYYY-MM-DD format)
  • Validates time components are at midnight (pure dates)
  • Luxon-based parsing for robust date validation

Usage Patterns

Example

vue
<template>
  <!-- Basic date selection -->
  <RDateField v-model="selectedDate" label="Select Date" displayFormat="med" />

  <!-- Multiple dates with constraints -->
  <RDateField
    v-model="eventDates"
    multiple
    label="Event Dates"
    :min="todayISO"
    :max="maxDateISO"
    displayFormat="medWithWeekday"
  />

  <!-- Read-only display -->
  <RDateField
    v-model="historicalDates"
    render-mode="read"
    displayFormat="full"
    multiple
  />

  <!-- Custom picker options -->
  <RDateField
    v-model="appointmentDate"
    label="Appointment"
    :firstDayOfWeek="1"
    :showWeek="true"
    displayFormat="huge"
  />
</template>

Data Flow

  1. Input: User types date or selects from picker
  2. Validation: Luxon validates ISO format and date validity
  3. Storage: ISO 8601 string stored in modelValue
  4. Display: Luxon formats for presentation using displayFormat
  5. Emission: Validated ISO string emitted to parent

Browser Compatibility

Automatic CSS injection handles native picker suppression across:

  • WebKit: Safari, Chrome, Edge (webkit-calendar-picker-indicator)
  • Mozilla: Firefox (moz-calendar-picker-indicator)
  • Microsoft: Legacy Edge, IE (ms-clear, ms-reveal)

This ensures consistent custom UI while preserving HTML5 input benefits like validation, accessibility, and mobile keyboard optimization.