Skip to content

Date Editor

Double-click a value to edit. Apply or Ctrl/Cmd+Enter saves the draft. Cancel, Escape or outside dismissal discards it. Read-only cells cannot open or commit an editor.

Source code
Vuevue
<template>
  <p>Double-click a value to edit. Apply saves; Cancel discards the draft.</p>
  <RevoGrid
    :source="source"
    :columns="columns"
    :plugins="plugins"
    :theme="isDark ? 'darkMaterial' : 'material'"
    style="height: 340px"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { currentThemeVue } from '../composables/useRandomData';
import RevoGrid from '@revolist/vue3-datagrid';
import { editorColumns, editorRows } from './editor-data';
const { isDark } = currentThemeVue();
const source = ref(editorRows());
const columns = editorColumns();
const plugins = [];
</script>
TypeScriptts
import { currentTheme } from '../composables/useRandomData';
import { defineCustomElements } from '@revolist/revogrid/loader';
import { editorColumns, editorRows } from './editor-data';
defineCustomElements();
export function load(parentSelector: string, rows = editorRows()) {
  const grid = document.createElement('revo-grid');
  grid.theme = currentTheme().isDark() ? 'darkMaterial' : 'material';
  grid.style.height = '340px';
  grid.columns = editorColumns();
  document.querySelector(parentSelector)?.append(grid);
  grid.source = rows;
  return () => grid.remove();
}
Reacttsx
import { currentTheme } from '../composables/useRandomData';
import { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { editorColumns, editorRows } from './editor-data';
export default function EditorDate({ rows }: { rows?: any[] }) {
  const columns = useMemo(editorColumns, []);
  const fallback = useMemo(editorRows, []);
  const plugins = useMemo(() => [], []);
  return (
    <>
      <p>
        Double-click a value to edit. Apply saves; Cancel discards the draft.
      </p>
      <RevoGrid
        source={rows?.length ? rows : fallback}
        columns={columns}
        plugins={plugins}
        theme={currentTheme().isDark() ? 'darkMaterial' : 'material'}
        style={{ height: '340px' }}
      />
    </>
  );
}
Angularts
import { currentTheme } from '../composables/useRandomData';
import { Component, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { editorColumns, editorRows } from './editor-data';
@Component({
  selector: 'editor-date-grid',
  standalone: true,
  imports: [RevoGrid],
  encapsulation: ViewEncapsulation.None,
  template: `<p>
      Double-click a value to edit. Apply saves; Cancel discards the draft.
    </p>
    <revo-grid
      [source]="source"
      [columns]="columns"
      [plugins]="plugins"
      [theme]="theme"
      style="height:340px"
    ></revo-grid>`,
})
export class EditorDateGridComponent {
  theme = currentTheme().isDark() ? 'darkMaterial' : 'material';
  source = editorRows();
  columns = editorColumns();
  plugins = [];
}
Editor configurationts
import type { ColumnRegular } from '@revolist/revogrid';
import { DateTimeEditor, dateCellTemplate } from '@revolist/revogrid-pro';
export const editorRows = () => [
  {
    name: 'Launch',
    value: '2026-10-12',
    range: { from: '2026-10-12', to: '2026-10-17' },
    multiple: ['2026-10-12', '2026-10-15'],
  },
  { name: 'Optional dates', value: null, range: null, multiple: [] },
];
export const editorColumns = (): ColumnRegular[] => [
  { prop: 'name', name: 'Task', size: 160, readonly: true },
  {
    prop: 'value',
    name: 'Single date',
    size: 180,
    editor: DateTimeEditor,
    cellTemplate: dateCellTemplate,
    dateEditor: {
      kind: 'date',
      calendar: { captionLayout: 'dropdown', showWeekNumber: true },
    },
  },
  {
    prop: 'range',
    name: 'Date range',
    size: 240,
    editor: DateTimeEditor,
    cellTemplate: dateCellTemplate,
    dateEditor: {
      kind: 'date',
      selection: 'range',
      calendar: { numberOfMonths: 2 },
    },
  },
  {
    prop: 'multiple',
    name: 'Multiple dates',
    size: 240,
    editor: DateTimeEditor,
    cellTemplate: dateCellTemplate,
    dateEditor: { kind: 'date', selection: 'multiple' },
  },
];

Use DateTimeEditor with dateEditor.kind: 'date', or register ColumnDate. Dates store civil ISO strings (YYYY-MM-DD) and never shift timezones. Select single, range ({ from, to }) or multiple (date array). Clear stores null, or [] for multiple selection.

dateEditor.calendar forwards the applicable shared CalendarPicker options: bounds, disabled dates and months, presets, number of months, navigation, captions, week numbers, calendar system, locale, direction, translations, validation and rendering callbacks. Controlled selection stays with the editor. Optional clear remains available; required and invalid drafts cannot Apply.

Existing Date, spreadsheet-date numbers and strings retain their representations through adapters. The independently published companion date package remains supported.

Use the progress presentation when a date range also needs a visual completion indicator. It uses the same shared calendar controls as the date editor above, with editable dates-only endpoints, dates-only captions, full-range tooltips and the approved full-cell progress styling.

Source code
TypeScriptts
import { defineCustomElements } from '@revolist/revogrid/loader';
import { editorTimeline, RowOddPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

defineCustomElements();

export function load(parentSelector: string) {
  const grid = document.createElement('revo-grid');
  grid.range = true;
  grid.className = 'rounded-lg overflow-hidden cell-border';

  grid.source = [
    { name: 'Project Planning', timeline: { from: '2024-01-01', to: '2024-01-30', progress: 50 } },
    { name: 'Development Phase', timeline: { from: '2024-04-01', to: '2024-09-30', progress: 75 } },
    { name: 'Testing Phase', timeline: { from: '2024-10-01', to: '2024-12-31', progress: 10 } },
    { name: 'Deployment', timeline: { from: '2025-01-01', to: '2025-02-28' } },
  ];

  grid.columns = [
    { prop: 'name', size: 200 },
    {
      name: 'Date range',
      prop: 'timeline',
      size: 200,
      cellTemplate: editorTimeline,
      thresholds: [
        { value: 0, className: 'low' },
        { value: 50, className: 'medium' },
        { value: 75, className: 'high' },
      ],
    },
  ];

  grid.plugins = [RowOddPlugin];

  const { isDark } = currentTheme();
  grid.theme = isDark() ? 'darkMaterial' : 'material';
  grid.style.minHeight = '400px';
  grid.hideAttribution = true;

  document.querySelector(parentSelector)?.appendChild(grid);
}
Vuevue
<template>
  <RevoGrid
    class="rounded-lg overflow-hidden cell-border"
    range
    :columns="columns"
    :source="source"
    :theme="isDark ? 'darkMaterial' : 'material'"
    :plugins="[RowOddPlugin]"
    hide-attribution
    style="min-height: 400px;"
  />
</template>

<script setup lang="ts">
import RevoGrid, { type ColumnRegular } from '@revolist/vue3-datagrid';
import { editorTimeline, RowOddPlugin } from '@revolist/revogrid-pro';
import { ref } from 'vue';
import { currentThemeVue } from '../composables/useRandomData';

const { isDark } = currentThemeVue();

const source = ref([
  { name: 'Project Planning', timeline: { from: '2024-01-01', to: '2024-01-30', progress: 50 } },
  { name: 'Development Phase', timeline: { from: '2024-04-01', to: '2024-09-30', progress: 75 } },
  { name: 'Testing Phase', timeline: { from: '2024-10-01', to: '2024-12-31', progress: 10 } },
  { name: 'Deployment', timeline: { from: '2025-01-01', to: '2025-02-28' } },
]);

const columns: ColumnRegular[] = [
  { prop: 'name', size: 200 },
  {
    name: 'Date range',
    prop: 'timeline',
    size: 200,
    cellTemplate: editorTimeline,
    thresholds: [
      { value: 0, className: 'low' },
      { value: 50, className: 'medium' },
      { value: 75, className: 'high' }
    ]
  },
];
</script> 
Reacttsx
import { useMemo } from 'react';
import { RevoGrid, type ColumnRegular } from '@revolist/react-datagrid';
import { editorTimeline, RowOddPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

function EditorTimeline() {
  const { isDark } = currentTheme();

  const source = useMemo(() => [
    { name: 'Project Planning', timeline: { from: '2024-01-01', to: '2024-01-30', progress: 50 } },
    { name: 'Development Phase', timeline: { from: '2024-04-01', to: '2024-09-30', progress: 75 } },
    { name: 'Testing Phase', timeline: { from: '2024-10-01', to: '2024-12-31', progress: 10 } },
    { name: 'Deployment', timeline: { from: '2025-01-01', to: '2025-02-28' } },
  ], []);

  const columns: ColumnRegular[] = useMemo(
    () => [
      { prop: 'name', size: 200 },
      {
        name: 'Date range',
        prop: 'timeline',
        size: 200,
        cellTemplate: editorTimeline,
        thresholds: [
          { value: 0, className: 'low' },
          { value: 50, className: 'medium' },
          { value: 75, className: 'high' },
        ],
      },
    ],
    []
  );

  const plugins = useMemo(() => [RowOddPlugin], []);

  return (
    <RevoGrid
      className="rounded-lg overflow-hidden cell-border"
      range
      source={source}
      columns={columns}
      plugins={plugins}
      theme={isDark() ? 'darkMaterial' : 'material'}
      hideAttribution
      style={{ minHeight: '400px' }}
    />
  );
}

export default EditorTimeline;
Angularts
import { Component, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { editorTimeline, RowOddPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

@Component({
  selector: 'editor-timeline-grid',
  standalone: true,
  imports: [RevoGrid],
  template: `
    <revo-grid
      class="rounded-lg overflow-hidden cell-border"
      [range]="true"
      [source]="source"
      [columns]="columns"
      [plugins]="plugins"
      [theme]="theme"
      [hideAttribution]="true"
      style="min-height: 400px;"
    ></revo-grid>
  `,
  encapsulation: ViewEncapsulation.None,
})
export class EditorTimelineGridComponent {
  theme = currentTheme().isDark() ? 'darkMaterial' : 'material';

  source = [
    { name: 'Project Planning', timeline: { from: '2024-01-01', to: '2024-01-30', progress: 50 } },
    { name: 'Development Phase', timeline: { from: '2024-04-01', to: '2024-09-30', progress: 75 } },
    { name: 'Testing Phase', timeline: { from: '2024-10-01', to: '2024-12-31', progress: 10 } },
    { name: 'Deployment', timeline: { from: '2025-01-01', to: '2025-02-28' } },
  ];

  columns = [
    { prop: 'name', size: 200 },
    {
      name: 'Date range',
      prop: 'timeline',
      size: 200,
      cellTemplate: editorTimeline,
      thresholds: [
        { value: 0, className: 'low' },
        { value: 50, className: 'medium' },
        { value: 75, className: 'high' },
      ],
    },
  ];

  plugins = [RowOddPlugin];
}

The existing editorTimeline cell template remains supported for { from, to, progress? } values. This is a date-range presentation, not a separate calendar implementation. Use dateEditor.selection: 'range' above for a plain date range.

Configure each timeline column with timelineOptions:

{
prop: 'timeline',
cellTemplate: editorTimeline,
timelineOptions: {
mode: 'dateTime', // 'date' (default), 'time', or 'dateTime'
locale: 'en-GB',
dateFormat: 'iso', // 'locale', 'eu', 'us', 'iso', or 'long'
timeFormat: '24h', // 'locale', '12h', or '24h'
},
}

The start and end buttons sit on opposite sides of the range. Hover over the range for its full dates and times. Select a start and end in the calendar, then choose Apply to save; Cancel or Escape discards the draft. Selecting the end button lets you adjust just the end date. Times use the configured timezone, or the browser’s local timezone by default. Date-only editing preserves date-only values; enabling time editing stores ISO timestamps.

The default date caption uses a compact range without weekdays. Read-only ranges retain full text contrast; progress fills the cell with a subtle tint and a colored bottom edge.

For multiple labeled ranges in one cell, use the Timeline Segment Editor.

Use dateEditor.text for picker labels, accessible popup names and validation messages, partial dateEditor.actions for Apply/Cancel/Clear, and dateEditor.calendar.translations for calendar controls. Calendar locale controls date presentation; timeZone can be set on the editor or the calendar options, with the editor taking precedence.

The same controls are used by existing product adapters: Gantt exposes datePicker and durationPicker, Audit History exposes auditHistoryPanel.datePicker, and Charts exposes navigation.rangeSelector.datePicker. Grouped date filters inherit the column’s dateEditor options. Product adapters retain their own bounds, timezone, validation and save commands; shared picker configuration supplies presentation and localized labels.

Type dates directly or use the calendar. Single dates have one input, ranges have separate endpoint inputs, and multiple selection accepts a semicolon-separated list. Datetime editors keep separate date and time controls. Invalid drafts remain visible and cannot Apply; Cancel discards them.

{
prop: 'due', editor: DateTimeEditor,
dateEditor: {
dateInput: { format: 'eu', placeholder: 'DD/MM/YYYY' },
calendar: {
minDate: '2026-01-01', maxDate: '2026-12-31',
isDateDisabled: date => date === '2026-12-25',
},
},
}

dateInput supports iso (default), eu, us or locale numeric Gregorian formats. ISO input is accepted in every mode. locale follows calendar.locale, including localized digits. Configure parse(text) and formatValue(isoDate) for application-specific formats, multipleSeparator for lists, or set dateInput: false for calendar-only controls. Selection and storage still use Gregorian civil ISO dates, including when the calendar displays another system.

Validation checks real dates (including leap years), bounds, disabled days/months, required values, ordered complete ranges, multiple-date counts/duplicates, range lengths, disabled interiors with excludeDisabled, and calendar.validateSelection. A custom validation message is displayed directly. Translate date, dates, invalidDate, outOfRange, disabledDate, invalidRange, selectionCount and requiredValue through dateEditor.text; the existing invalid message remains a fallback. Range endpoint labels are accessible names; the fields display dates only.

ColumnDate includes a compact date renderer. When registering DateTimeEditor directly, add cellTemplate: dateCellTemplate from @revolist/revogrid-pro to use the same presentation. timeCellTemplate and dateTimeCellTemplate are available for the other value kinds.

Ranges show a compact caption, multiple dates show individual chips, and additional dates use a +N badge. Hover or accessible text exposes every full date, including years. Cell labels inherit the calendar locale/system, configured date input format and time presentation. Civil dates never shift timezones; timestamps use the configured editor timezone.

Set dateEditor.display.maxVisibleDates to change the default of two chips (minimum one), or dateEditor.display.formatValue to format an individual projected date/time. Custom cellTemplate renderers remain supported and stored values are unchanged.