Beyond the Prompt A one-day AG Grid & Bryntum conference • 19th May 26 Learn more




Core Features

Advanced Features

JavaScript Data GridNotes

Enterprise

Notes let users attach comments to individual cells without storing note text in row data. Cells with notes are marked in the grid, note actions are available from the context menu, hovering a noted cell opens the built-in resizable note editor, and Shift + F2 opens or creates a note for the focused cell when notes are allowed.

Enabling Notes Copy Link

Notes are enabled by providing a notesDataSource to the grid. The datasource has two required methods getNote() and setNote() and is responsible for managing the state of the notes for the grid. To ensure stable row ids getRowId() is required.

To add a new note either right-click a cell to open the context menu or press Shift + F2. Hovering a cell with a note will display the note popup. Use noteShowDelay and noteHideDelay to control how quickly note popups appear and disappear on hover.

notesDataSourceCopy Link
NotesDataSource | FullWidthNotesDataSource
Provide a data source to control where notes are stored and retrieved. Can be updated to enable, disable, or replace Notes at runtime.
const gridOptions = {
    getRowId: (params) => String(params.data.id),
    notesDataSource: {
        getNote: ({ rowNode, column }) => notesStore[rowNode.id]?.[column.getColId()],
        setNote: ({ rowNode, column, note }) => {
            const row = (notesStore[rowNode.id] ??= {});

            if (note === undefined) {
                delete row[column.getColId()];
            } else {
                row[column.getColId()] = note;
            }
        },
    },

    // other grid options ...
}

Notes Trigger Copy Link

Use noteTrigger to control whether existing notes open on hover or on left-click. hover is the default. When using click, noteShowDelay no longer applies, but noteHideDelay still controls how long the note stays open after the pointer leaves the cell or popup.

Click mode follows the same passive note rules as hover mode: notes still do not open for the cell currently being edited.

const gridOptions = {
    noteTrigger: 'click',

    // other grid options ...
}
noteTriggerCopy Link
'hover' | 'click'
default: 'hover'
Changes how existing notes are opened.
  • 'hover' - Existing notes open when hovering a noted cell or full width row.
  • 'click' - Existing notes open when clicking a noted cell or full width row.
  • noteShowDelayCopy Link
    number
    default: 180
    The delay in milliseconds before a note is shown when hovering a noted cell. Only applies when noteTrigger = 'hover'.
    noteHideDelayCopy Link
    number
    default: 220
    The delay in milliseconds before a note is hidden after the pointer leaves a noted cell or note popup.

    Metadata Copy Link

    Built-in note metadata, including author, createdAt, and updatedAt, is rendered exactly as provided by your datasource.

    The built-in note editor only updates the note text. If notes created from the built-in UI should also include metadata, stamp it inside notesDataSource.setNote(). The example below includes an Authenticated User input to simulate the current user being stamped into saved notes.

    const getCurrentUser = () => document.getElementById('current-user').value;
    const getDisplayTimestamp = () => new Date().toLocaleString('en-GB');
    
    const gridOptions = {
        notesDataSource: {
            setNote: ({ rowNode, column, note }) => {
                const row = (noteStore[rowNode.id] ??= {});
                const colId = column.getColId();
                const existingNote = row[colId];
    
                if (note === undefined) {
                    delete row[colId];
                } else {
                    row[colId] = {
                        ...existingNote,
                        ...note,
                        author: getCurrentUser(),
                        createdAt: existingNote?.createdAt ?? getDisplayTimestamp(),
                        updatedAt: getDisplayTimestamp(),
                    };
                }
            },
        },
    
        // other grid options ...
    }

    Custom Data Copy Link

    Use note.metadata to store any application-defined data alongside the built-in note fields. The Grid preserves this data when the built-in editor updates an existing note, but the built-in note popup does not render it.

    The example below stores metadata.type and metadata.priority on notes, then uses application-level cell classes and CSS variables to style note indicators differently. This keeps custom Note data in your datasource while letting your app decide how that data should affect presentation.

    const gridOptions = {
        defaultColDef: {
            cellClass: ({ node, column }) => {
                const colId = column.getColId();
                const metadata = getCellNoteMetadata(node.id, colId);
    
                if (metadata) {
                    const { type, priority } = metadata;
                    return [`note-type-${type}`, `note-priority-${priority}`]
                }
            },
        },
        notesDataSource: {
            setNote: ({ rowNode, column, note }) => {
                const key = `${rowNode.id}::${column.getColId()}`;
                const existingNote = noteStore.get(key);
    
                if (note === undefined) {
                    noteStore.delete(key);
                } else {
                    noteStore.set(key, {
                        ...existingNote,
                        ...note,
                        metadata: existingNote?.metadata ?? { type: 'team', priority: 'medium' },
                    });
                }
            },
        },
    
        // other grid options ...
    }

    Read-Only Notes Copy Link

    Set Note.readOnly = true to make a note view-only. Read-only notes can still be opened from hover or click based on noteTrigger, the context menu, or Shift + F2, but they cannot be edited or removed through the built-in UI. The grid API can still update or remove read-only notes programmatically.

    Athlete has an editable note. Country and Sport have read-only notes, so they can be viewed but not edited or removed through the built-in UI.

    noteStore.set(noteKey('3', 'country'), {
        text: 'Check the latest federation naming guidance for this country.',
        author: 'AG Grid',
        updatedAt: '27 Mar 2026, 14:30',
        readOnly: true,
    });
    

    Suppressing Note Actions Copy Link

    Use colDef.suppressNoteActions to suppress built-in note actions for a column or specific row. Suppressed cells still allow existing notes to be viewed through the configured note trigger and through getNote(), but add/edit/remove actions and note creation shortcuts are blocked.

    Year and Sport suppress built-in note actions. Existing notes on those cells can still be viewed normally, while other columns keep the standard add, edit, and remove behaviour.

    const gridOptions = {
        columnDefs: [
            { field: 'athlete' },
            { field: 'year', suppressNoteActions: true },
            { field: 'sport', suppressNoteActions: params => params.data?.sport === 'Swimming' },
        ],
    
        // other grid options ...
    }

    Full Width Rows Copy Link

    To support adding notes to full width rows ensure the notesDataSource implements the FullWidthNotesDataSource interface. The interface requires supportsFullWidthRows:true to be set on the notesDataSource.

    The example below includes both regular notes on cells and notes on full width rows in the same datasource. Full width rows use a separate note identity. Instead of receiving a column, the datasource receives location: 'fullWidthRow' and an optional pinned value when in embedFullWidthRows mode.

    const notesStore = new Map();
    
    const gridOptions = {
        getRowId: (params) => String(params.data.id),
        notesDataSource: {
            // Enable support for Full Width Rows
            supportsFullWidthRows: true,
            getNote: (params) =>
                params.location === 'fullWidthRow'
                    ? notesStore.get(getFullWidthNoteKey(params.rowNode.id))
                    : notesStore.get(getNoteKey(params.rowNode.id, params.column.getColId())),
            setNote: (params) => {
                const key =
                    params.location === 'fullWidthRow'
                        ? getFullWidthNoteKey(params.rowNode.id)
                        : getNoteKey(params.rowNode.id, params.column.getColId());
                if (params.note === undefined) {
                    notesStore.delete(key);
                } else {
                    notesStore.set(key, params.note);
                }
            },
        },
    
        // other grid options ...
    }
    notesStore.set('2', {
        text: 'This note belongs to a full width row.',
    });
    

    Embedded Full Width Rows Copy Link

    When embedFullWidthRows=true, the datasource still receives location: 'fullWidthRow', but pinned identifies whether the note belongs to the left, centre, or right rendered section so that the notesDataSource can save the note appropriately.

    Feature Interaction Copy Link

    Context Menu Copy Link

    When the ContextMenuModule is registered, the note actions are included automatically. If you customise getContextMenuItems(), include the built-in note item to keep the standard note actions:

    const gridOptions = {
        getContextMenuItems: () => ['note', 'copy', 'export'],
    
        // other grid options ...
    }

    The built-in note item expands based on the current cell state:

    • Add Note when the cell has no note and note creation is allowed.
    • Edit Note and Remove Note when the existing note is editable.
    • View Note, plus a disabled Remove Note, when the existing note is read-only.
    • Disabled note actions when the cell is suppressed. Existing suppressed notes still show View Note.

    Keyboard Shortcuts Copy Link

    Shift + F2 opens an existing note for the focused cell, or creates a new note if the cell allows notes and does not already have one. Plain F2 keeps the normal cell editing behaviour.

    Cell Editing Copy Link

    Notes are not displayed if the cell is currently being edited. Hovering that cell or pressing Shift + F2 will have no effect until editing is complete.

    API Copy Link

    Use the grid API to read, write, remove and refresh notes programmatically. This is useful when notes are edited from application UI outside the grid, or when the underlying note store changes directly. The API example also shows how to set readOnly on a note payload.

    In the example below:

    • clicking a cell selects it and syncs the toolbar controls automatically.
    • Save via API updates the note with setNote(), including setting or clearing readOnly.
    • Remove via API clears the note
    • Mutate Store Directly plus Refresh Notes shows how to resync the grid after external store updates.

    Grid Options Copy Link

    noteTriggerCopy Link
    'hover' | 'click'
    default: 'hover'
    Changes how existing notes are opened.
  • 'hover' - Existing notes open when hovering a noted cell or full width row.
  • 'click' - Existing notes open when clicking a noted cell or full width row.
  • noteShowDelayCopy Link
    number
    default: 180
    The delay in milliseconds before a note is shown when hovering a noted cell. Only applies when noteTrigger = 'hover'.
    noteHideDelayCopy Link
    number
    default: 220
    The delay in milliseconds before a note is hidden after the pointer leaves a noted cell or note popup.

    API Reference Copy Link

    getNoteCopy Link
    Function
    Return the current note for a cell.
    setNoteCopy Link
    Function
    Set or remove the note for a cell. Pass note: undefined to remove the note.
    refreshNotesCopy Link
    Function
    Refresh note presence for the currently rendered cells.

    NotesDataSource Copy Link

    Properties available on the NotesDataSource<TMetadata = any> interface.

    getNoteCopy Link
    Function
    Return the note for the given cell.
    setNoteCopy Link
    Function
    Set or clear the note for the given cell.
    Function
    Initialise the data source so that the user can take a reference to the gridApi if needed.
    destroyCopy Link
    Function
    Called by the grid when the data source is being disposed.

    FullWidthNotesDataSource Copy Link

    Properties available on the FullWidthNotesDataSource<TMetadata = any> interface.

    supportsFullWidthRowsCopy Link
    true
    Enables full width row notes for this datasource.
    getNoteCopy Link
    Function
    Return the note for the given cell or full width row.
    setNoteCopy Link
    Function
    Set or clear the note for the given cell or full width row.
    Function
    Initialise the data source so that the user can take a reference to the gridApi if needed.
    destroyCopy Link
    Function
    Called by the grid when the data source is being disposed.

    Note Copy Link

    string
    Text content of the note.
    readOnlyCopy Link
    boolean
    Set to true to make this note readonly.
    authorCopy Link
    string
    Optional author of the note.
    createdAtCopy Link
    string
    Optional creation timestamp.
    updatedAtCopy Link
    string
    Optional updated timestamp.
    metadataCopy Link
    TMetadata
    Optional application metadata to be associated with this note.

    RefreshNotesParams Copy Link

    Only refresh the provided rowNodes. If undefined refresh all rows.
    columnsCopy Link
    (string | Column)[]
    Only refresh the provided columns. If undefined refresh all columns.