React Data GridMoment.js date Cell Type - Step-by-Step Guide
On this page
Overview
This guide shows how to create a custom time cell type using the Moment.js (opens new window) library. Users can format times using the Moment.js API.
Difficulty: Beginner
Time: ~15 minutes
Libraries: moment
Complete Example
What You'll Build
A cell that:
- Displays time values as formatted text
- Accepts
timeFormatoptions for customization (e.g.,HH:mm,h:mm:ss a) - Validates time input using Moment.js
- Auto-corrects time format when
correctFormatis enabled
Prerequisites
npm install moment
Step 1: Import Dependencies
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import { getRenderer } from 'handsontable/renderers';
import { getEditor } from 'handsontable/editors';
import { registerCellType } from 'handsontable/cellTypes';
import moment from 'moment';
registerAllModules();
Why this matters:
momenthandles time parsing, validation, and formattinggetRenderer('text')andgetEditor('text')reuse Handsontable's built-in text renderer and editorregisterCellTyperegisters the custom cell type for use in column config
Step 2: Create the Renderer
We reuse the built-in text renderer, which displays the time value as plain text:
renderer: getRenderer('text')
Step 3: Create the Validator
The validator parses the input using Moment.js and checks it against the configured timeFormat. It handles Unix timestamps, two-digit shorthand (e.g., 9 becomes 9:00), and auto-correction:
validator: function(value, callback) {
const timeFormat = this.timeFormat ?? 'h:mm:ss a';
let valid = true;
if (value === null) {
value = '';
}
value = /^\d{3,}$/.test(value) ? parseInt(value, 10) : value;
const twoDigitValue = /^\d{1,2}$/.test(value);
if (twoDigitValue) {
value += ':00';
}
const date = moment(value, [
'YYYY-MM-DDTHH:mm:ss.SSSZ',
'X', // Unix timestamp
'x' // Unix ms timestamp
], true).isValid() ?
moment(value) : moment(value, timeFormat);
let isValidTime = date.isValid();
// is it in the specified format
let isValidFormat = moment(value, timeFormat, true).isValid() && !twoDigitValue;
if (this.allowEmpty && value === '') {
isValidTime = true;
isValidFormat = true;
}
if (!isValidTime) {
valid = false;
}
if (!isValidTime && isValidFormat) {
valid = true;
}
if (isValidTime && !isValidFormat) {
if (this.correctFormat === true) {
const correctedValue = date.format(timeFormat);
this.instance.setDataAtCell(this.visualRow, this.visualCol, correctedValue, 'timeValidator');
valid = true;
} else {
valid = false;
}
}
callback(valid);
}
What's happening:
- Converts numeric-only input (3+ digits) to integers for Unix timestamp parsing
- Appends
:00to 1-2 digit values (e.g.,9becomes9:00) - Tries ISO 8601 and Unix timestamp formats first, then falls back to the configured
timeFormat - If
correctFormatis enabled, auto-corrects valid but misformatted times
Step 4: Create the Editor
We reuse the built-in text editor — a simple text input for editing the time value:
editor: getEditor('text')
Step 5: Complete Cell Type Definition
Put all the pieces together and register the cell type:
const cellTimeTypeDefinition = {
renderer: getRenderer('text'),
validator: function(value, callback) {
// ... validator code from Step 3
},
editor: getEditor('text'),
};
registerCellType('moment-time', cellTimeTypeDefinition);
What's happening:
- renderer: Uses the built-in
textrenderer to display the time value - validator: Custom validator that validates and optionally corrects time format using Moment.js
- editor: Uses the built-in
texteditor for simple text input - registerCellType: Registers the
moment-timecell type for use in column config
Step 6: Use in Handsontable
registerCellType('moment-time', cellTimeTypeDefinition);
const hotOptions: Handsontable.GridSettings = {
data,
colHeaders: ['Item Name', 'Category', 'Lead Engineer', 'Arrival Time', 'Cost'],
autoRowSize: true,
rowHeaders: true,
height: 'auto',
width: '100%',
autoWrapRow: true,
headerClassName: 'htLeft',
columns: [
{ data: 'itemName', type: 'text', width: 130 },
{ data: 'category', type: 'text', width: 120 },
{ data: 'leadEngineer', type: 'text', width: 150 },
{
data: 'time',
type: 'moment-time',
width: 150,
timeFormat: 'HH:mm',
correctFormat: true,
},
{
data: 'cost',
type: 'numeric',
width: 120,
className: 'htRight',
numericFormat: {
pattern: '$0,0.00',
culture: 'en-US',
},
},
],
licenseKey: 'non-commercial-and-evaluation',
};
const hot = new Handsontable(container, hotOptions);
Key configuration:
type: 'moment-time'- uses the custom cell type on the Arrival Time columntimeFormat: 'HH:mm'- the Moment.js format string for 24-hour timecorrectFormat: true- automatically reformats valid times to the expected formatheaderClassName: 'htLeft'- left-aligns all column headers
How It Works - Complete Flow
- Initial Render: Cell displays the time value as plain text using the
textrenderer - User clicks cell: The built-in text editor opens for editing
- User enters time: Input like
9,14:30, or a Unix timestamp is accepted - Validation: Moment.js checks the format and time validity; auto-corrects if
correctFormatis enabled - Save: Valid values are saved to the cell; invalid values are rejected