Framework:Javascript Data GridAngular Data GridReact Data GridVue Data Grid

React Data Grid: Date Component

You can create your own date components, and AG Grid will use them every time it needs to ask the user for a date value. The date components are currently used in date filters.

Simple Date Component

Below is a simple example of filter component as a Hook:

export default forwardRef((props, ref) => {
   const [date, setDate] = useState(null);
   const [picker, setPicker] = useState(null);
   const refFlatPickr = useRef();
   const refInput = useRef();


   const onDateChanged = (selectedDates) => {

   useEffect(() => {
       setPicker(flatpickr(refFlatPickr.current, {
           onChange: onDateChanged,
           dateFormat: 'd/m/Y',
           wrap: true
   }, []);

   useEffect(() => {
       if (picker) {
   }, [picker]);

   useEffect(() => {
       //Callback after the state is set. This is where we tell ag-grid that the date has changed so
       //it will proceed with the filtering and we can then expect AG Grid to call us back to getDate
       if (picker) {
   }, [date, picker]);

   useImperativeHandle(ref, () => ({
       //          METHODS REQUIRED BY AG-GRID
       getDate() {
           //ag-grid will call us here when in need to check what the current date value is hold by this
           return date;

       setDate(date) {
           //ag-grid will call us here when it needs this component to update the date that it holds.

       //          AG-GRID OPTIONAL METHODS

       setInputPlaceholder(placeholder) {
           if (refInput.current) {
               refInput.current.setAttribute('placeholder', placeholder);

       setInputAriaLabel(label) {
           if (refInput.current) {
               refInput.current.setAttribute('aria-label', label);

   // inlining styles to make simpler the component
   return (
       <div className="ag-input-wrapper custom-date-filter" role="presentation" ref={refFlatPickr}>
           <input type="text" ref={refInput} data-input style={{ width: "100%" }} />
           <a class='input-button' title='clear' data-clear>
               <i class='fa fa-times'></i>

And here is the same example as a Class-based Component:

export default class CustomDateComponent extends Component {
   constructor(props) {

       this.state = {
           date: null

   render() {
       //Inlining styles to make simpler the component
       return (
           <div className="ag-input-wrapper custom-date-filter" role="presentation" ref="flatpickr">
               <input type="text" ref="eInput" data-input style={{width: "100%"}}/>
               <a class='input-button' title='clear' data-clear>
                   <i class='fa fa-times'></i>

   componentDidMount() {
       this.picker = flatpickr(this.refs.flatpickr, {
           onChange: this.onDateChanged.bind(this),
           dateFormat: 'd/m/Y',
           wrap: true

       this.eInput = this.refs.eInput;



   getDate() {
       //ag-grid will call us here when in need to check what the current date value is hold by this

   setDate(date) {
       //ag-grid will call us here when it needs this component to update the date that it holds.


   setInputPlaceholder(placeholder) {
       this.eInput.setAttribute('placeholder', placeholder);

   setInputAriaLabel(label) {
       this.eInput.setAttribute('aria-label', label);


   updateAndNotifyAgGrid(date) {
       //Callback after the state is set. This is where we tell ag-grid that the date has changed so
       //it will proceed with the filtering and we can then expect AG Grid to call us back to getDate
       this.setState({date}, this.props.onDateChanged);


   onDateChanged = (selectedDates) => {
       this.setState({date: selectedDates[0]});

Example: Custom Date Component

The example below shows how to register a custom date component that contains an extra floating calendar picker rendered from the filter field. The problem with this approach is that we have no control over third party components and therefore no way to implement a preventDefault when the user clicks on the Calendar Picker (for more info see Custom Floating Filter Example). Our way of fixing this problem is to add the ag-custom-component-popup class to the floating calendar.

Registering Date Components

By default the grid will use the browser provided date picker for Chrome and Firefox (as we think it's nice), but for all other browsers it will just provide a simple text field. You can use your own date picker to AG Grid by providing a custom Date Component as follows:

   frameworkComponents={{ agDateInput: CustomDateComponent }}
   ...other properties...

Please see Provided Components for more information about overrided AG Grid provided components (as we're doing here by overriding agDateInput).

Custom Date Interface

The interface for a custom date component is as follows:

interface {
   // Returns the current date represented by this editor
   getDate(): Date;

   // Sets the date represented by this component
   setDate(date: Date): void;

   // Optional methods

   // Sets the input text placeholder
   setInputPlaceholder(placeholder: string): void;

   // Sets the input text aria label
   setInputAriaLabel(label: string): void;

Note that if you're using Hooks for Grid Components that have lifecycle/callbacks that the grid will call (for example, the getDate callback from an Date Component), then you'll need to expose them with forwardRef & useImperativeHandle.

Please refer to the Hook documentation (or the examples on this page) for more information.

Custom Filter Parameters

When a React component is instantiated the grid will make the grid APIs, a number of utility methods as well as the cell & row values available to you via props - the interface for what is provided is documented below.

Properties available on the IDateParams interface.

Method for component to tell AG Grid that the date has changed.
onDateChanged = () => void;
filterParams: IDateFilterParams;

interface IDateFilterParams {
  // Required if the data for the column are not native JS `Date` objects. 
  comparator?: IDateComparatorFunc;
  // This is only used if a date component is not provided.
  // By default the grid will use the browser date picker in Chrome and Firefox and a plain text box for all other browsers
  // (This is because Chrome and Firefox are the only current browsers providing a decent out-of-the-box date picker).
  // If this property is set to `true`, the browser date picker will be used regardless of the browser type.
  // If set to `false`, a plain text box will be used for all browsers. 
  browserDatePicker?: boolean;
  // This is the minimum year that must be entered in a date field for the value to be considered valid. Default: `1000` 
  minValidYear?: number;
  // If `true`, the `'inRange'` filter option will include values equal to the start and end of the range. 
  inRangeInclusive?: boolean;
  // If `true`, blank (`null` or `undefined`) values will pass the `'equals'` filter option. 
  includeBlanksInEquals?: boolean;
  // If `true`, blank (`null` or `undefined`) values will pass the `'lessThan'` and `'lessThanOrEqual'` filter options. 
  includeBlanksInLessThan?: boolean;
  // If `true`, blank (`null` or `undefined`) values will pass the `'greaterThan'` and `'greaterThanOrEqual'` filter options. 
  includeBlanksInGreaterThan?: boolean;
  // If `true`, blank (`null` or `undefined`) values will pass the `'inRange'` filter option. 
  includeBlanksInRange?: boolean;
  // Array of filter options to present to the user. See [Filter Options](/filter-provided-simple/#simple-filter-options) for all options available to each filter type. 
  filterOptions?: (IFilterOptionDef | string)[];
  // The default filter option to be selected. 
  defaultOption?: string;
  // By default, the two conditions are combined using `AND`.
  // You can change this default by setting this property.
  // Options: `AND`, `OR` 
  defaultJoinOperator?: JoinOperator;
  // If `true`, the filter will only allow one condition.
  // Default: `false` 
  suppressAndOrCondition?: boolean;
  // By default, only one condition is shown, and a second is made visible once a first condition has been entered.
  // Set this to `true` to always show both conditions. 
  // In this case the second condition will be disabled until a first condition has been entered.
  // Default: `false` 
  alwaysShowBothConditions?: boolean;
  buttons?: FilterButtonType[];
  closeOnApply?: boolean;
  debounceMs?: number;
  // The column this filter is for. 
  column: Column;
  // The column definition for the column. 
  colDef: ColDef;
  // The row model, helpful for looking up data values if needed.
  // If the filter needs to know which rows are
  // a) in the table,
  // b) currently visible (i.e. not already filtered),
  // c) which groups,
  // d) what order - all of this can be read from the rowModel. 
  rowModel: IRowModel;
  // A function callback to be called when the filter changes. The
  // grid will then respond by filtering the grid data. The callback
  // takes one optional parameter which, if included, will get merged
  // to the FilterChangedEvent object (useful for passing additional
  // information to anyone listening to this event, however such extra
  // attributes are not used by the grid). 
  filterChangedCallback: (additionalEventAttributes?: any) => void;
  // A function callback, to be optionally called, when the filter UI changes.
  // The grid will respond with emitting a FilterModifiedEvent.
  // Apart from emitting the event, the grid takes no further action. 
  filterModifiedCallback: () => void;
  // A function callback for the filter to get cell values from the row data.
  // Call with a node to be given the value for that filter's column for that node.
  // The callback takes care of selecting the right column definition and deciding whether to use valueGetter or field etc.
  // This is useful in, for example, creating an Excel style filter,
  // where the filter needs to lookup available values to allow the user to select from. 
  valueGetter: (rowNode: RowNode) => any;
  // A function callback, call with a node to be told whether the node passes all filters except the current filter.
  // This is useful if you want to only present to the user values that this filter can filter given the status of the other filters.
  // The set filter uses this to remove from the list,
  // items that are no longer available due to the state of other filters (like Excel type filtering). 
  doesRowPassOtherFilter: (rowNode: RowNode) => boolean;
  api: GridApi;
  columnApi: ColumnApi;
  // The context as provided on `gridOptions.context` 
  context: any;

interface IDateComparatorFunc {
    (filterLocalDateAtMidnight: Date, cellValue: any) : number

interface IFilterOptionDef {
  // A unique key that does not clash with the built-in filter keys. 
  displayKey: string;
  // Display name for the filter. Can be replaced by a locale-specific value using a `localeTextFunc`. 
  displayName: string;
  // Custom filter logic that returns a boolean based on the `filterValue` and `cellValue`. 
  test: (filterValue: any, cellValue: any) => boolean;
  // Optionally hide the filter input field. 
  hideFilterInput?: boolean;

type JoinOperator = 'AND' | 'OR'

type FilterButtonType = 
    | 'clear' 
    | 'reset' 
    | 'cancel'

interface IRowModel {
  // Returns the rowNode at the given index. 
  getRow(index: number): RowNode | undefined;
  // Returns the rowNode for given id. 
  getRowNode(id: string): RowNode | undefined;
  // This is legacy, not used by AG Grid, but keeping for backward compatibility 
  getRowCount(): number;
  getTopLevelRowCount(): number;
  getTopLevelRowDisplayedIndex(topLevelIndex: number): number;
  // Returns the row index at the given pixel 
  getRowIndexAtPixel(pixel: number): number;
  // Returns true if the provided rowNode is in the list of rows to render 
  isRowPresent(rowNode: RowNode): boolean;
  // Returns row top and bottom for a given row 
  getRowBounds(index: number): RowBounds | null;
  // Returns true if this model has no rows, regardless of model filter. EG if rows present, but filtered
  // out, this still returns false. If it returns true, then the grid shows the 'no rows' overlay - but we
  // don't show that overlay if the rows are just filtered out. 
  isEmpty(): boolean;
  // Returns true if no rows (either no rows at all, or the rows are filtered out). This is what the grid
  // uses to know if there are rows to render or not. 
  isRowsToRender(): boolean;
  // Returns all rows in range that should be selected. If there is a gap in range (non ClientSideRowModel) then
  // then no rows should be returned 
  getNodesInRangeForSelection(first: RowNode, last: RowNode | null): RowNode[];
  // Iterate through each node. What this does depends on the model type. For clientSide, goes through
  // all nodes. For serverSide, goes through what's loaded in memory. 
  forEachNode(callback: (rowNode: RowNode, index: number) => void): void;
  // The base class returns the type. We use this instead of 'instanceof' as the client might provide
  // their own implementation of the models in the future. 
  getType(): string;
  // It tells us if this row model knows about the last row that it can produce. This is used by the
  // PaginationPanel, if last row is not found, then the 'last' button is disabled and the last page is
  // not shown. This is always true for ClientSideRowModel. It toggles for InfiniteRowModel. 
  isLastRowIndexKnown(): boolean;
  // Used by CSRM only - is makes sure there are now estimated row heights within the range. 
  ensureRowHeightsValid(startPixel: number, endPixel: number, startLimitIndex: number, endLimitIndex: number): boolean;
  // Gets called after grid is initialised. What happens depends on row model. Client Side will take rowData
  // from gridOptions, the other row models will start calling their datasources. 
  start(): void;

interface RowBounds {
  rowTop: number;
  rowHeight: number;
  rowIndex?: number;