Undo and Redo
Set history on Builder to enable built-in undo and redo support for structural edits and value changes. The builder records inverse actions internally, so history stays smaller than full-query snapshots and still works with drag-and-drop, cloning, deletes, and inline edits.
History support
import '@vojtechportes/react-query-builder/styles.css';import React, { useState } from 'react';import {Builder,type DenormalizedQuery,type IBuilderStateChange,} from '@vojtechportes/react-query-builder';export const MyBuilder = () => {const [data, setData] = useState<DenormalizedQuery>(initialData);const [historyState, setHistoryState] = useState({canUndo: false,canRedo: false,});const handleStateChange = (state: IBuilderStateChange) => {setHistoryState({canUndo: state.canUndo,canRedo: state.canRedo,});};return (<><Builderfields={fields}data={data}draggablecloneablehistory={{ maxEntries: 30, controls: true }}onStateChange={handleStateChange}onChange={setData}/><p>Undo available: {String(historyState.canUndo)}</p><p>Redo available: {String(historyState.canRedo)}</p></>);};
How to enable it
history=enables history with default behavior.history={{ maxEntries, controls }}enables history with custom configuration.maxEntrieslimits how many undo steps are kept in memory.controlscontrols whether the built-in Undo and Redo buttons are rendered.
What gets tracked
- Adding, removing, cloning, and editing rules.
- Adding, removing, cloning, and editing groups.
- Drag-and-drop reordering and movement between groups.
- Changes driven through the builder UI that emit through
onChange.
State callbacks
onStateChangeincludescanUndoandcanRedoso custom toolbars can stay in sync.- The built-in controls already use those flags and render disabled when no action is available.
- Redo history is cleared after a new forward edit, which matches standard editor behavior.
Custom HistoryControls
Use components.HistoryControls when you want to change the placement or surrounding layout of the built-in history controls without reimplementing undo and redo behavior yourself.
HistoryControls override
import '@vojtechportes/react-query-builder/styles.css';const components = {HistoryControls: ({undoButton,redoButton,canUndo,canRedo,}) => (<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}><span>History</span>{undoButton}{redoButton}<small>{canUndo ? 'Undo ready' : 'No undo yet'}</small><small>{canRedo ? 'Redo ready' : 'No redo yet'}</small></div>),};<Builderfields={fields}data={data}historycomponents={components}onChange={setData}/>;// HistoryControls receives:// undoButton: React.ReactNode// redoButton: React.ReactNode// canUndo: boolean// canRedo: boolean// onUndo: () => void// onRedo: () => void
- The override receives ready-to-render
undoButtonandredoButtonnodes. - It also receives
canUndo,canRedo,onUndo, andonRedowhen you need custom wrappers or auxiliary UI. - This lets you reorder, wrap, or annotate the default buttons without having to rebuild their disabled-state logic.
Related docs