Skip to content

Autofill

The AutoFillPlugin adds spreadsheet-style drag fill to RevoGrid. Users select one or more cells, drag the fill handle, and RevoGrid fills the target range with the best matching strategy.

For a richer spreadsheet experience, pair it with AutoFillPreviewPlugin. The preview plugin shows ghost values while the user is dragging, but it does not write anything to the data store until the drop-time autofill is accepted.

Source code
TypeScript ts
// src/components/autofill/Autofill.ts

import { defineCustomElements } from '@revolist/revogrid/loader';
import { type ColumnRegular, type DataType } from '@revolist/revogrid';
import { AutoFillPlugin, AutoFillPreviewPlugin, ColumnStretchPlugin, RangeSelectionLimitPlugin, RowOddPlugin, TooltipPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

defineCustomElements();
const { isDark } = currentTheme();

const strategyDescriptions: Record<string, string> = {
  dateUnitSequence: 'Continues dates by day or month while preserving visible formats such as yyyy/mm/dd.',
  timeSequence: 'Continues time values using the detected interval, for example 30 minute steps.',
  weekdayMonthName: 'Cycles weekday or month names forward while preserving full or short labels.',
  textNumberSequence: 'Increments numbers embedded in text while preserving prefixes and zero padding.',
  dateSequence: 'Continues ISO date strings using a consistent day interval.',
  dateSequenceWithInterval: 'Extends date values from the last selected date using the detected interval.',
  linearNumericSequence: 'Continues numeric values using the selected arithmetic step.',
  singleNumericStep: 'Creates a +1 numeric sequence from one selected number.',
  booleanCycle: 'Repeats boolean-like pairs such as Yes and No, True and False, or On and Off.',
  textSequence: 'Continues text labels with numeric suffixes, such as Task 1, Task 2, Task 3.',
  copyFallback: 'Copies the selected values when no sequence strategy matches.',
};

function strategyColumn(name: string, prop: string, size: number): ColumnRegular {
  return {
    name,
    prop,
    size,
    columnTemplate: (h, column) =>
      h('span', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px' } }, [
        h('span', null, column.name || ''),
        h('span', {
          'data-tooltip': strategyDescriptions[String(column.prop)] || '',
          'tooltip-position': 'bottom',
          'tooltip-type': 'info',
          style: {
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            width: '16px',
            height: '16px',
            borderRadius: '50%',
            border: '1px solid currentColor',
            fontSize: '11px',
            lineHeight: '16px',
            opacity: '0.72',
          },
        }, '?'),
      ]),
  };
}

const columns: ColumnRegular[] = [
  strategyColumn('Date Unit Sequence', 'dateUnitSequence', 230),
  strategyColumn('Time Sequence', 'timeSequence', 210),
  strategyColumn('Weekday And Month Names', 'weekdayMonthName', 250),
  strategyColumn('Text Number Sequence', 'textNumberSequence', 250),
  strategyColumn('Date Sequence', 'dateSequence', 220),
  strategyColumn('Date Sequence With Interval', 'dateSequenceWithInterval', 290),
  strategyColumn('Linear Numeric Sequence', 'linearNumericSequence', 270),
  strategyColumn('Single Numeric Step', 'singleNumericStep', 250),
  strategyColumn('Boolean Cycle', 'booleanCycle', 220),
  strategyColumn('Text Sequence', 'textSequence', 220),
  strategyColumn('Copy Fallback', 'copyFallback', 210),
];

function createRows(): DataType[] {
  const rows: DataType[] = Array.from({ length: 80 }, () => ({}));
  const samples: DataType[] = [
    {
      dateUnitSequence: '2024/01/15',
      timeSequence: '09:00',
      weekdayMonthName: 'Monday',
      textNumberSequence: 'INV-0099',
      dateSequence: '2024-02-01',
      dateSequenceWithInterval: '2024-03-01',
      linearNumericSequence: 10,
      singleNumericStep: 7,
      booleanCycle: 'Yes',
      textSequence: 'Task 1',
      copyFallback: 'North',
    },
    {
      dateUnitSequence: '2024/02/15',
      timeSequence: '09:30',
      weekdayMonthName: 'Tuesday',
      textNumberSequence: 'INV-0100',
      dateSequence: '2024-02-03',
      dateSequenceWithInterval: '2024-03-08',
      linearNumericSequence: 15,
      booleanCycle: 'No',
      textSequence: 'Task 2',
      copyFallback: 'South',
    },
    {
      dateUnitSequence: '2024/03/15',
      timeSequence: '10:00',
      weekdayMonthName: 'Wednesday',
      textNumberSequence: 'INV-0101',
      dateSequence: '2024-02-05',
      dateSequenceWithInterval: '2024-03-15',
      linearNumericSequence: 20,
      booleanCycle: 'Yes',
      textSequence: 'Task 3',
      copyFallback: 'West',
    },
    {
      dateUnitSequence: '2024/04/15',
      timeSequence: '10:30',
      weekdayMonthName: 'Thursday',
      textNumberSequence: 'INV-0102',
      dateSequence: '2024-02-07',
      dateSequenceWithInterval: '2024-03-22',
      linearNumericSequence: 25,
      booleanCycle: 'No',
      textSequence: 'Task 4',
      copyFallback: 'East',
    },
    {
      dateUnitSequence: '2024/05/15',
      timeSequence: '11:00',
      weekdayMonthName: 'Friday',
      textNumberSequence: 'INV-0103',
      dateSequence: '2024-02-09',
      dateSequenceWithInterval: '2024-03-29',
      linearNumericSequence: 30,
      booleanCycle: 'Yes',
      textSequence: 'Task 5',
      copyFallback: 'Central',
    },
  ];

  samples.forEach((sample, index) => {
    Object.assign(rows[index], sample);
  });

  return rows;
}

/**
 * Initializes the Autofill RevoGrid component within the specified parent element.
 * @param parentSelector - A CSS selector string for the parent element where the grid will be appended.
 */
export function load(parentSelector: string) {
  const container = document.createElement('div');
  container.className = 'rounded-lg overflow-hidden';
  container.style.minHeight = '560px';

  const grid = document.createElement('revo-grid') as HTMLRevoGridElement;
  grid.range = true;
  grid.theme = isDark() ? 'darkMaterial' : 'material';
  grid.hideAttribution = true;
  grid.columns = columns;
  grid.stretch = 'all';
  grid.rangeSelectionLimit = { mode: 'column' };
  grid.plugins = [AutoFillPlugin, AutoFillPreviewPlugin, RangeSelectionLimitPlugin, TooltipPlugin, RowOddPlugin, ColumnStretchPlugin];

  container.appendChild(grid);
  document.querySelector(parentSelector)?.appendChild(container);

  grid.source = createRows();

  return () => container.remove();
}
Vue vue
<template>
  <VGrid
    class="rounded-lg overflow-hidden grow"
    range
    :theme="isDark ? 'darkMaterial' : 'material'"
    :columns="columns"
    :source="rows"
    :plugins="plugins"
    :range-selection-limit="rangeSelectionLimit"
    stretch="all"
    hide-attribution
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { currentThemeVue } from '../composables/useRandomData';
import { type ColumnRegular, type DataType, VGrid } from '@revolist/vue3-datagrid';
import { AutoFillPlugin, AutoFillPreviewPlugin, ColumnStretchPlugin, RangeSelectionLimitPlugin, RowOddPlugin, TooltipPlugin } from '@revolist/revogrid-pro';

const { isDark } = currentThemeVue();

const strategyDescriptions: Record<string, string> = {
  dateUnitSequence: 'Continues dates by day or month while preserving visible formats such as yyyy/mm/dd.',
  timeSequence: 'Continues time values using the detected interval, for example 30 minute steps.',
  weekdayMonthName: 'Cycles weekday or month names forward while preserving full or short labels.',
  textNumberSequence: 'Increments numbers embedded in text while preserving prefixes and zero padding.',
  dateSequence: 'Continues ISO date strings using a consistent day interval.',
  dateSequenceWithInterval: 'Extends date values from the last selected date using the detected interval.',
  linearNumericSequence: 'Continues numeric values using the selected arithmetic step.',
  singleNumericStep: 'Creates a +1 numeric sequence from one selected number.',
  booleanCycle: 'Repeats boolean-like pairs such as Yes and No, True and False, or On and Off.',
  textSequence: 'Continues text labels with numeric suffixes, such as Task 1, Task 2, Task 3.',
  copyFallback: 'Copies the selected values when no sequence strategy matches.',
};

function strategyColumn(name: string, prop: string, size: number): ColumnRegular {
  return {
    name,
    prop,
    size,
    columnTemplate: (h, column) =>
      h('span', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px' } }, [
        h('span', null, column.name || ''),
        h('span', {
          'data-tooltip': strategyDescriptions[String(column.prop)] || '',
          'tooltip-position': 'bottom',
          'tooltip-type': 'info',
          style: {
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            width: '16px',
            height: '16px',
            borderRadius: '50%',
            border: '1px solid currentColor',
            fontSize: '11px',
            lineHeight: '16px',
            opacity: '0.72',
          },
        }, '?'),
      ]),
  };
}

const columns: ColumnRegular[] = [
  strategyColumn('Date Unit Sequence', 'dateUnitSequence', 230),
  strategyColumn('Time Sequence', 'timeSequence', 210),
  strategyColumn('Weekday And Month Names', 'weekdayMonthName', 250),
  strategyColumn('Text Number Sequence', 'textNumberSequence', 250),
  strategyColumn('Date Sequence', 'dateSequence', 220),
  strategyColumn('Date Sequence With Interval', 'dateSequenceWithInterval', 290),
  strategyColumn('Linear Numeric Sequence', 'linearNumericSequence', 270),
  strategyColumn('Single Numeric Step', 'singleNumericStep', 250),
  strategyColumn('Boolean Cycle', 'booleanCycle', 220),
  strategyColumn('Text Sequence', 'textSequence', 220),
  strategyColumn('Copy Fallback', 'copyFallback', 210),
];

const plugins = [AutoFillPlugin, AutoFillPreviewPlugin, RangeSelectionLimitPlugin, TooltipPlugin, RowOddPlugin, ColumnStretchPlugin];
const rangeSelectionLimit = { mode: 'column' as const };

function createRows(): DataType[] {
  const rows: DataType[] = Array.from({ length: 80 }, () => ({}));
  const samples: DataType[] = [
    {
      dateUnitSequence: '2024/01/15',
      timeSequence: '09:00',
      weekdayMonthName: 'Monday',
      textNumberSequence: 'INV-0099',
      dateSequence: '2024-02-01',
      dateSequenceWithInterval: '2024-03-01',
      linearNumericSequence: 10,
      singleNumericStep: 7,
      booleanCycle: 'Yes',
      textSequence: 'Task 1',
      copyFallback: 'North',
    },
    {
      dateUnitSequence: '2024/02/15',
      timeSequence: '09:30',
      weekdayMonthName: 'Tuesday',
      textNumberSequence: 'INV-0100',
      dateSequence: '2024-02-03',
      dateSequenceWithInterval: '2024-03-08',
      linearNumericSequence: 15,
      booleanCycle: 'No',
      textSequence: 'Task 2',
      copyFallback: 'South',
    },
    {
      dateUnitSequence: '2024/03/15',
      timeSequence: '10:00',
      weekdayMonthName: 'Wednesday',
      textNumberSequence: 'INV-0101',
      dateSequence: '2024-02-05',
      dateSequenceWithInterval: '2024-03-15',
      linearNumericSequence: 20,
      booleanCycle: 'Yes',
      textSequence: 'Task 3',
      copyFallback: 'West',
    },
    {
      dateUnitSequence: '2024/04/15',
      timeSequence: '10:30',
      weekdayMonthName: 'Thursday',
      textNumberSequence: 'INV-0102',
      dateSequence: '2024-02-07',
      dateSequenceWithInterval: '2024-03-22',
      linearNumericSequence: 25,
      booleanCycle: 'No',
      textSequence: 'Task 4',
      copyFallback: 'East',
    },
    {
      dateUnitSequence: '2024/05/15',
      timeSequence: '11:00',
      weekdayMonthName: 'Friday',
      textNumberSequence: 'INV-0103',
      dateSequence: '2024-02-09',
      dateSequenceWithInterval: '2024-03-29',
      linearNumericSequence: 30,
      booleanCycle: 'Yes',
      textSequence: 'Task 5',
      copyFallback: 'Central',
    },
  ];

  samples.forEach((sample, index) => {
    Object.assign(rows[index], sample);
  });

  return rows;
}

const rows = ref<DataType[]>(createRows());
</script>
React tsx
// src/components/autofill/Autofill.tsx

import React, { useMemo, useState } from 'react';
import { RevoGrid, type DataType, type ColumnRegular, type ColumnGrouping } from '@revolist/react-datagrid';
import { AutoFillPlugin, AutoFillPreviewPlugin, ColumnStretchPlugin, RangeSelectionLimitPlugin, RowOddPlugin, TooltipPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

const strategyDescriptions: Record<string, string> = {
  dateUnitSequence: 'Continues dates by day or month while preserving visible formats such as yyyy/mm/dd.',
  timeSequence: 'Continues time values using the detected interval, for example 30 minute steps.',
  weekdayMonthName: 'Cycles weekday or month names forward while preserving full or short labels.',
  textNumberSequence: 'Increments numbers embedded in text while preserving prefixes and zero padding.',
  dateSequence: 'Continues ISO date strings using a consistent day interval.',
  dateSequenceWithInterval: 'Extends date values from the last selected date using the detected interval.',
  linearNumericSequence: 'Continues numeric values using the selected arithmetic step.',
  singleNumericStep: 'Creates a +1 numeric sequence from one selected number.',
  booleanCycle: 'Repeats boolean-like pairs such as Yes and No, True and False, or On and Off.',
  textSequence: 'Continues text labels with numeric suffixes, such as Task 1, Task 2, Task 3.',
  copyFallback: 'Copies the selected values when no sequence strategy matches.',
};

function strategyColumn(name: string, prop: string, size: number): ColumnRegular {
  return {
    name,
    prop,
    size,
    columnTemplate: (h, column) =>
      h('span', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px' } }, [
        h('span', null, column.name || ''),
        h('span', {
          'data-tooltip': strategyDescriptions[String(column.prop)] || '',
          'tooltip-position': 'bottom',
          'tooltip-type': 'info',
          style: {
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            width: '16px',
            height: '16px',
            borderRadius: '50%',
            border: '1px solid currentColor',
            fontSize: '11px',
            lineHeight: '16px',
            opacity: '0.72',
          },
        }, '?'),
      ]),
  };
}

function createRows(): DataType[] {
  const rows: DataType[] = Array.from({ length: 80 }, () => ({}));
  const samples: DataType[] = [
    {
      dateUnitSequence: '2024/01/15',
      timeSequence: '09:00',
      weekdayMonthName: 'Monday',
      textNumberSequence: 'INV-0099',
      dateSequence: '2024-02-01',
      dateSequenceWithInterval: '2024-03-01',
      linearNumericSequence: 10,
      singleNumericStep: 7,
      booleanCycle: 'Yes',
      textSequence: 'Task 1',
      copyFallback: 'North',
    },
    {
      dateUnitSequence: '2024/02/15',
      timeSequence: '09:30',
      weekdayMonthName: 'Tuesday',
      textNumberSequence: 'INV-0100',
      dateSequence: '2024-02-03',
      dateSequenceWithInterval: '2024-03-08',
      linearNumericSequence: 15,
      booleanCycle: 'No',
      textSequence: 'Task 2',
      copyFallback: 'South',
    },
    {
      dateUnitSequence: '2024/03/15',
      timeSequence: '10:00',
      weekdayMonthName: 'Wednesday',
      textNumberSequence: 'INV-0101',
      dateSequence: '2024-02-05',
      dateSequenceWithInterval: '2024-03-15',
      linearNumericSequence: 20,
      booleanCycle: 'Yes',
      textSequence: 'Task 3',
      copyFallback: 'West',
    },
    {
      dateUnitSequence: '2024/04/15',
      timeSequence: '10:30',
      weekdayMonthName: 'Thursday',
      textNumberSequence: 'INV-0102',
      dateSequence: '2024-02-07',
      dateSequenceWithInterval: '2024-03-22',
      linearNumericSequence: 25,
      booleanCycle: 'No',
      textSequence: 'Task 4',
      copyFallback: 'East',
    },
    {
      dateUnitSequence: '2024/05/15',
      timeSequence: '11:00',
      weekdayMonthName: 'Friday',
      textNumberSequence: 'INV-0103',
      dateSequence: '2024-02-09',
      dateSequenceWithInterval: '2024-03-29',
      linearNumericSequence: 30,
      booleanCycle: 'Yes',
      textSequence: 'Task 5',
      copyFallback: 'Central',
    },
  ];

  samples.forEach((sample, index) => {
    Object.assign(rows[index], sample);
  });

  return rows;
}

function Autofill() {
  const { isDark } = currentTheme();
  const theme = useMemo(() => (isDark() ? 'darkMaterial' : 'material'), [isDark]);

  const columns: (ColumnRegular | ColumnGrouping)[] = useMemo(
    () => [
      strategyColumn('Date Unit Sequence', 'dateUnitSequence', 230),
      strategyColumn('Time Sequence', 'timeSequence', 210),
      strategyColumn('Weekday And Month Names', 'weekdayMonthName', 250),
      strategyColumn('Text Number Sequence', 'textNumberSequence', 250),
      strategyColumn('Date Sequence', 'dateSequence', 220),
      strategyColumn('Date Sequence With Interval', 'dateSequenceWithInterval', 290),
      strategyColumn('Linear Numeric Sequence', 'linearNumericSequence', 270),
      strategyColumn('Single Numeric Step', 'singleNumericStep', 250),
      strategyColumn('Boolean Cycle', 'booleanCycle', 220),
      strategyColumn('Text Sequence', 'textSequence', 220),
      strategyColumn('Copy Fallback', 'copyFallback', 210),
    ],
    [],
  );

  const plugins = useMemo(() => [AutoFillPlugin, AutoFillPreviewPlugin, RangeSelectionLimitPlugin, TooltipPlugin, RowOddPlugin, ColumnStretchPlugin], []);
  const rangeSelectionLimit = useMemo(() => ({ mode: 'column' as const }), []);

  const [rows] = useState<DataType[]>(createRows);

  return (
    <RevoGrid
      className="rounded-lg overflow-hidden grow"
      range
      theme={theme}
      columns={columns}
      source={rows}
      plugins={plugins}
      rangeSelectionLimit={rangeSelectionLimit}
      stretch="all"
      hide-attribution
    />
  );
}

export default Autofill;
Angular ts
import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation, type OnInit } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { type ColumnRegular, type DataType } from '@revolist/revogrid';
import { AutoFillPlugin, AutoFillPreviewPlugin, ColumnStretchPlugin, RangeSelectionLimitPlugin, RowOddPlugin, TooltipPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';

const strategyDescriptions: Record<string, string> = {
  dateUnitSequence: 'Continues dates by day or month while preserving visible formats such as yyyy/mm/dd.',
  timeSequence: 'Continues time values using the detected interval, for example 30 minute steps.',
  weekdayMonthName: 'Cycles weekday or month names forward while preserving full or short labels.',
  textNumberSequence: 'Increments numbers embedded in text while preserving prefixes and zero padding.',
  dateSequence: 'Continues ISO date strings using a consistent day interval.',
  dateSequenceWithInterval: 'Extends date values from the last selected date using the detected interval.',
  linearNumericSequence: 'Continues numeric values using the selected arithmetic step.',
  singleNumericStep: 'Creates a +1 numeric sequence from one selected number.',
  booleanCycle: 'Repeats boolean-like pairs such as Yes and No, True and False, or On and Off.',
  textSequence: 'Continues text labels with numeric suffixes, such as Task 1, Task 2, Task 3.',
  copyFallback: 'Copies the selected values when no sequence strategy matches.',
};

function strategyColumn(name: string, prop: string, size: number): ColumnRegular {
  return {
    name,
    prop,
    size,
    columnTemplate: (h, column) =>
      h('span', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px' } }, [
        h('span', null, column.name || ''),
        h('span', {
          'data-tooltip': strategyDescriptions[String(column.prop)] || '',
          'tooltip-position': 'bottom',
          'tooltip-type': 'info',
          style: {
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            width: '16px',
            height: '16px',
            borderRadius: '50%',
            border: '1px solid currentColor',
            fontSize: '11px',
            lineHeight: '16px',
            opacity: '0.72',
          },
        }, '?'),
      ]),
  };
}

@Component({
  selector: 'autofill-grid',
  standalone: true,
  schemas: [NO_ERRORS_SCHEMA],
  imports: [RevoGrid],
  template: `
    <revo-grid
      class="rounded-lg overflow-hidden"
      [range]="true"
      [theme]="theme"
      [columns]="columns"
      [source]="rows"
      [plugins]="plugins"
      [rangeSelectionLimit]="rangeSelectionLimit"
      [stretch]="'all'"
      [hideAttribution]="true"
      style="min-height: 560px; min-width: 600px;"
    ></revo-grid>
  `,
})
export class AutofillGridComponent implements OnInit {
  theme = currentTheme().isDark() ? 'darkMaterial' : 'material';

  columns = [
    strategyColumn('Date Unit Sequence', 'dateUnitSequence', 230),
    strategyColumn('Time Sequence', 'timeSequence', 210),
    strategyColumn('Weekday And Month Names', 'weekdayMonthName', 250),
    strategyColumn('Text Number Sequence', 'textNumberSequence', 250),
    strategyColumn('Date Sequence', 'dateSequence', 220),
    strategyColumn('Date Sequence With Interval', 'dateSequenceWithInterval', 290),
    strategyColumn('Linear Numeric Sequence', 'linearNumericSequence', 270),
    strategyColumn('Single Numeric Step', 'singleNumericStep', 250),
    strategyColumn('Boolean Cycle', 'booleanCycle', 220),
    strategyColumn('Text Sequence', 'textSequence', 220),
    strategyColumn('Copy Fallback', 'copyFallback', 210),
  ];

  plugins = [AutoFillPlugin, AutoFillPreviewPlugin, RangeSelectionLimitPlugin, TooltipPlugin, RowOddPlugin, ColumnStretchPlugin];
  rangeSelectionLimit = { mode: 'column' as const };

  rows: DataType[] = [];

  ngOnInit() {
    this.rows = createRows();
  }
}

function createRows(): DataType[] {
  const rows: DataType[] = Array.from({ length: 80 }, () => ({}));
  const samples: DataType[] = [
    {
      dateUnitSequence: '2024/01/15',
      timeSequence: '09:00',
      weekdayMonthName: 'Monday',
      textNumberSequence: 'INV-0099',
      dateSequence: '2024-02-01',
      dateSequenceWithInterval: '2024-03-01',
      linearNumericSequence: 10,
      singleNumericStep: 7,
      booleanCycle: 'Yes',
      textSequence: 'Task 1',
      copyFallback: 'North',
    },
    {
      dateUnitSequence: '2024/02/15',
      timeSequence: '09:30',
      weekdayMonthName: 'Tuesday',
      textNumberSequence: 'INV-0100',
      dateSequence: '2024-02-03',
      dateSequenceWithInterval: '2024-03-08',
      linearNumericSequence: 15,
      booleanCycle: 'No',
      textSequence: 'Task 2',
      copyFallback: 'South',
    },
    {
      dateUnitSequence: '2024/03/15',
      timeSequence: '10:00',
      weekdayMonthName: 'Wednesday',
      textNumberSequence: 'INV-0101',
      dateSequence: '2024-02-05',
      dateSequenceWithInterval: '2024-03-15',
      linearNumericSequence: 20,
      booleanCycle: 'Yes',
      textSequence: 'Task 3',
      copyFallback: 'West',
    },
    {
      dateUnitSequence: '2024/04/15',
      timeSequence: '10:30',
      weekdayMonthName: 'Thursday',
      textNumberSequence: 'INV-0102',
      dateSequence: '2024-02-07',
      dateSequenceWithInterval: '2024-03-22',
      linearNumericSequence: 25,
      booleanCycle: 'No',
      textSequence: 'Task 4',
      copyFallback: 'East',
    },
    {
      dateUnitSequence: '2024/05/15',
      timeSequence: '11:00',
      weekdayMonthName: 'Friday',
      textNumberSequence: 'INV-0103',
      dateSequence: '2024-02-09',
      dateSequenceWithInterval: '2024-03-29',
      linearNumericSequence: 30,
      booleanCycle: 'Yes',
      textSequence: 'Task 5',
      copyFallback: 'Central',
    },
  ];

  samples.forEach((sample, index) => {
    Object.assign(rows[index], sample);
  });

  return rows;
}
import { AutoFillPlugin, AutoFillPreviewPlugin } from '@revolist/revogrid-pro';
const grid = document.createElement('revo-grid');
grid.plugins = [AutoFillPlugin, AutoFillPreviewPlugin];

Use only AutoFillPlugin when you want values to appear only after mouse release. Add AutoFillPreviewPlugin when users should see the predicted values before they drop the mouse.

  1. Select a source cell or range.
  2. Drag the small autofill handle from the selection corner.
  3. Ghost values appear in the temporary target range when preview is enabled.
  4. Release the mouse to commit the same values that were previewed.
  5. Pressing escape, clearing the temporary range, or changing the source clears the preview.

Existing selected source cells are not visually replaced by preview values. The preview only appears in the autofill target range.

AutoFill strategies are checked from most specific to most general. If no sequence strategy can safely infer a pattern, RevoGrid repeats the selected values with copy fallback.

StrategyUser behaviorExample
Linear numeric sequenceContinues a selected numeric interval.1, 3 -> 5, 7
Single numeric stepExtends one selected number by +1.10 -> 11, 12
Number in textContinues labels with embedded numbers and preserves padding.INV-099 -> INV-100; 1st Floor -> 2nd Floor
Weekday namesContinues English weekday labels and wraps the week.Mon, Tue -> Wed
Month namesContinues English month labels and wraps the year.Jan, Feb -> Mar
Date unit sequenceContinues daily, weekly, monthly, quarterly, and yearly date intervals.2024-12-04, 2024-12-05 -> 2024-12-06
Time sequenceContinues HH:mm and HH:mm:ss time intervals.09:00, 09:30 -> 10:00
Boolean cycleRepeats boolean-like toggle pairs.Yes, No -> Yes, No
Text suffix sequenceKeeps compatibility with existing Book 1, Book 2 fills.Book 1, Book 2 -> Book 3
Copy fallbackRepeats selected values when the pattern is plain or ambiguous.Draft, Approved -> Draft, Approved

Select two or more numeric cells to preserve an interval. For example, selecting 100 and 110 continues with 120, 130, and so on. Selecting one numeric cell uses a simple +1 sequence.

AutoFill understands numbers inside labels, not only numbers at the end. It keeps the visible text shape stable when the selected values are consistent.

Item 001 -> Item 002
INV-099 -> INV-100
1st Floor, 2nd Floor -> 3rd Floor

If labels use different prefixes, suffixes, or number formats, RevoGrid falls back to copying the selected values instead of guessing.

Dates preserve the selected visible format when possible:

2024-12-04 -> 2024-12-05
2024/12/04 -> 2024/12/05
12/04/2024 -> 12/05/2024

Monthly, quarterly, and yearly fills are inferred from consistent month steps. Time fills preserve HH:mm or HH:mm:ss and wrap across midnight.

Weekday and month strategies support English full names and three-letter labels. The output format follows the source format:

Monday, Tuesday -> Wednesday
Mon, Tue -> Wed
January, February -> March
Jan, Feb -> Mar

Boolean cycle supports true/false, yes/no, and on/off. String pairs require both values in the selected range, so a single Yes cell is copied instead of turning into an inferred toggle.

Copy fallback is intentional. It handles plain text, mixed values, and unsupported patterns by repeating the selected values exactly. This keeps AutoFill predictable for status columns and other business data where guessing a sequence would be surprising.

Developers can register custom strategies for domain-specific patterns. Custom strategies run before copy fallback, so they can override generic copy behavior.

import type { AutoFillStrategy } from '@revolist/revogrid-pro';
const priorityStrategy: AutoFillStrategy = (selectedData, direction, targetRange, context) => {
// Return a matrix when your strategy supports the selection.
// Return null to let the next strategy try.
return null;
};
AutoFillPlugin.registerStrategy(priorityStrategy);

Return null when a strategy is not confident. Preview and final apply share the same strategy list, so a custom strategy automatically affects both behaviors.