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

> Implement undo redo for Dear ImGui text input fields. Learn how the stb_textedit library handles Ctrl Z Ctrl Y and explore the ImGuiInputTextFlags_NoUndoRedo flag for custom control.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-14

---

**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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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:

```cpp
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`](https://github.com/ocornut/imgui/blob/main/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.

```cpp
// 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.

```cpp
// 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`](https://github.com/ocornut/imgui/blob/main/imgui.h) | Defines `ImGuiInputTextFlags_NoUndoRedo` and public API flags (lines 1276-1279) |
| [`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp) | Implements `InputTextEx`, shortcut detection (lines 5125-5127), and undo forwarding (line 5213) |
| [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) | Declares `ImGuiInputTextState` and its `Stb` member |
| [`imstb_textedit.h`](https://github.com/ocornut/imgui/blob/main/imstb_textedit.h) | Contains `StbUndoState` and `StbUndoRecord` structures for low-level history management |
| [`misc/cpp/imgui_stdlib.h`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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.