How to Implement Undo/Redo for Text Input Fields in Dear ImGui

Dear ImGui provides built-in undo/redo functionality for text input fields via the stb_textedit library, automatically handling Ctrl+Z and Ctrl+Y shortcuts and exposing control through the ImGuiInputTextFlags_NoUndoRedo flag.

Implementing undo/redo functionality for text input fields in Dear ImGui requires no external libraries or complex state management because the ocornut/imgui repository already integrates a complete history system. The widgets InputText, InputTextMultiline, and InputTextWithHint automatically track every insertion and deletion through an internal undo stack that persists across focus changes.

How Dear ImGui's Undo/Redo System Works

The undo/redo mechanism relies on a tight integration between Dear ImGui's widget state and the stb_textedit helper library. Each text field maintains its own circular buffer of edit records that captures character-level changes.

The Internal State Structure

Every active text input owns an ImGuiInputTextState structure declared in imgui_internal.h. Inside this state lives an ImStb::StbUndoState instance (accessible via state->Stb->undostate) that manages the history as a circular buffer of ImStb::StbUndoRecord objects.

These records store:

  • Where the change occurred (cursor position)
  • The length of inserted or deleted characters
  • Copies of inserted characters when necessary

The fields undo_point, redo_point, undo_char_point, and redo_char_point track the current position in the undo/redo timeline.

Recording Edit Operations

Whenever a user modifies text, the widget generates history records automatically. In ImGui::InputTextEx (imgui_widgets.cpp around line 4554), calls to InsertChars() or DeleteChars() invoke stb_text_createundo() to push a new StbUndoRecord onto the stack. This happens transparently during normal text manipulation, ensuring every keystroke is reversible without manual intervention.

Handling Keyboard Shortcuts

Keyboard shortcut detection occurs in the main input-processing loop of InputTextEx (lines 5125-5127):

  1. is_undo is set when Shortcut(Ctrl+Z) returns true
  2. is_redo is set when Shortcut(Ctrl+Y) or Shortcut(Ctrl+Shift+Z) returns true

When either flag triggers, the widget forwards the request to the stb-textedit engine at line 5213:

state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);

The ImGuiInputTextState::OnKeyPressed method then calls stb_text_undo() or stb_text_redo(), which restores the buffer to the appropriate previous or next state and updates the cursor and selection accordingly.

Persisting History Across Focus Changes

Undo/redo history survives when users click away from and return to a text field. When InputTextEx reactivates a widget with the same ID, it reuses the existing ImGuiInputTextState (lines 4864-4865 in imgui_widgets.cpp). This preserves the StbUndoState stack, allowing users to continue undoing operations after temporarily focusing another element.

Enabling and Disabling Undo/Redo

Enabled by default: No flags are required—the undo stack initializes automatically when you create an input field.

Disabled explicitly: Pass ImGuiInputTextFlags_NoUndoRedo to prevent the engine from allocating history buffers, which is useful when managing your own history or minimizing memory overhead.

// Standard usage—undo/redo works automatically
static char buffer1[256] = "";
ImGui::InputText("With Undo", buffer1, IM_ARRAYSIZE(buffer1));

// Disable the built-in system
static char buffer2[256] = "";
ImGui::InputText("Without Undo", buffer2, IM_ARRAYSIZE(buffer2), 
                 ImGuiInputTextFlags_NoUndoRedo);

Advanced: Custom History Persistence

For applications requiring session persistence or custom history logic, you can access the internal structures directly. Retrieve the active state via ImGui::GetCurrentContext()->InputTextState, then serialize the undo_point, undo_rec[], and character buffers from state->Stb->undostate.

To prevent a widget's undo buffer from surviving after destruction, call ImGui::ClearActiveID() before removing the field.

// Example: Serialize before closing
if (ImGui::IsWindowCollapsed() && ImGui::GetCurrentContext()->InputTextState.ID != 0)
{
    ImGuiInputTextState* state = &ImGui::GetCurrentContext()->InputTextState;
    // Access state->Stb->undostate.undo_rec[N] and undo_char_buf[N] for storage
}

// Later: Restore by re-creating the widget with the same ID and 
// manually copying saved records back into state->Stb->undostate

Key Source Files and Structures

File Purpose
imgui.h Defines ImGuiInputTextFlags_NoUndoRedo and public API flags (lines 1276-1279)
imgui_widgets.cpp Implements InputTextEx, shortcut detection (lines 5125-5127), and undo forwarding (line 5213)
imgui_internal.h Declares ImGuiInputTextState and its Stb member
imstb_textedit.h Contains StbUndoState and StbUndoRecord structures for low-level history management
misc/cpp/imgui_stdlib.h Provides std::string wrappers that respect undo/redo flags

Summary

  • Dear ImGui's text inputs (InputText, InputTextMultiline, InputTextWithHint) provide undo/redo by default using the stb_textedit library.
  • History records are created automatically in ImGui::InputTextEx via stb_text_createundo() whenever characters are inserted or deleted.
  • Keyboard shortcuts Ctrl+Z (undo) and Ctrl+Y or Ctrl+Shift+Z (redo) are detected in the widget's main loop and forwarded to state->OnKeyPressed().
  • State persistence occurs because ImGuiInputTextState is reused when reactivating widgets with the same ID, preserving the StbUndoState buffer.
  • Opt-out is available via ImGuiInputTextFlags_NoUndoRedo, and custom persistence is possible by accessing ImGui::GetCurrentContext()->InputTextState.

Frequently Asked Questions

Is undo/redo enabled by default in Dear ImGui text inputs?

Yes. Every InputText, InputTextMultiline, and InputTextWithHint widget automatically creates an internal StbUndoState buffer when initialized. Users can immediately use Ctrl+Z and Ctrl+Y without setting any flags or writing additional code.

How do I disable undo/redo for a specific input field?

Pass the ImGuiInputTextFlags_NoUndoRedo flag when calling the input function. This prevents the allocation of undo records and disables the Ctrl+Z and Ctrl+Y shortcuts for that specific widget, as defined in imgui.h lines 1276-1279.

Can I persist undo history across application sessions?

Yes, but it requires manual serialization. Access the active ImGuiInputTextState through ImGui::GetCurrentContext()->InputTextState, then read the Stb->undostate structure including undo_rec[] arrays and character buffers. Store these before closing the application, and restore them after recreating the widget with the same ID.

What keyboard shortcuts trigger undo/redo in Dear ImGui?

According to the implementation in imgui_widgets.cpp (lines 5125-5127), Ctrl+Z triggers undo, while Ctrl+Y or Ctrl+Shift+Z triggers redo. These shortcuts are processed within the InputTextEx function and forwarded to the stb_textedit engine via STB_TEXTEDIT_K_UNDO and STB_TEXTEDIT_K_REDO constants.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →