Dear ImGui Advanced Text Input with Callbacks: A Complete Developer Guide

TLDR: Dear ImGui's InputText, InputTextMultiline, and InputTextWithHint widgets support a flexible ImGuiInputTextCallback system defined in imgui.h, enabling dynamic buffer resizing, character filtering, TAB completion, and history navigation through dedicated event flags.

Dear ImGui enables advanced text input with callbacks that extend the basic InputText widget into a flexible editing framework. By supplying callback flags and user functions, developers can intercept keystrokes, resize buffers dynamically, and implement IDE-style auto-completion. In the ocornut/imgui repository, this behavior is driven by the core InputTextEx implementation declared in imgui_internal.h and the shared per-context ImGuiInputTextState.

How the Callback API Works

The public API lives in imgui.h and exposes three entry points:

bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
bool InputTextMultiline(...);
bool InputTextWithHint(...);

These functions follow the same signature and are routed through imgui_widgets.cpp to the internal InputTextEx implementation. When any callback flag is present, InputTextEx populates an ImGuiInputTextCallbackData structure and invokes the user-provided function. The callback can inspect data->EventFlag to determine the reason for the call and modify the buffer or cursor state accordingly.

Supported Callback Flags

The ImGuiInputTextFlags_ enum in imgui.h enumerates the events that InputTextEx can forward:

  • ImGuiInputTextFlags_CallbackResize — Requests a resize of the buffer; commonly used for dynamic strings.
  • ImGuiInputTextFlags_CallbackEdit — Called after any edit operation.
  • ImGuiInputTextFlags_CallbackAlways — Called on every frame while the widget is active.
  • ImGuiInputTextFlags_CallbackCharFilter — Allows filtering or replacing incoming characters.
  • ImGuiInputTextFlags_CallbackCompletion — Triggered when TAB is pressed.
  • ImGuiInputTextFlags_CallbackHistory — Triggered when ↑ or ↓ arrow keys are pressed.

Internal State and Buffer Safety

All active text inputs share a per-context ImGuiInputTextState instance stored in g.InputTextState. This structure holds the buffer, cursor position, selection range, and a temporary backup called CallbackTextBackup. The backup enables the CallbackEdit and CallbackAlways mechanisms to safely modify the buffer while preserving undo and redo history. This state is defined in imgui_internal.h.

Auto-Resizing std::string with CallbackResize

A common pattern is to use std::string with the Resize callback. The helper wrapper lives in misc/cpp/imgui_stdlib.cpp and defines a small InputTextCallback_UserData structure. It sets up a callback that expands the std::string when the buffer overflows, then forwards the call to the core InputText function.

// Wrapper automatically adds ImGuiInputTextFlags_CallbackResize
static std::string name = "Bob";
ImGui::InputText("Name", &name);

The wrapper internally adds the ImGuiInputTextFlags_CallbackResize flag together with a small callback that expands the std::string when needed, as implemented in misc/cpp/imgui_stdlib.cpp.

Filtering Characters with CallbackCharFilter

You can reject specific characters by returning 1 inside a CallbackCharFilter handler. The callback checks data->EventFlag to confirm the event type.

int MyCharFilter(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter)
    {
        if (data->EventChar >= '0' && data->EventChar <= '9')
            return 1;               // 1 = discard
    }
    return 0;                       // 0 = keep
}

// Usage
char buf[128] = "";
ImGui::InputText("Alpha only", buf, sizeof(buf),
                 ImGuiInputTextFlags_CallbackCharFilter,
                 MyCharFilter);

Growing a Raw C Buffer with CallbackResize

For dynamically allocated C strings, the resize callback receives the desired buffer size and must update data->Buf and data->BufSize directly.

int MyResizeCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
    {
        char* new_buf = (char*)realloc(data->Buf, data->BufSize * 2);
        data->Buf = new_buf;
        data->BufSize *= 2;
    }
    return 0;
}

// Usage
static char* dyn_buf = (char*)malloc(64);
static size_t dyn_buf_size = 64;
ImGui::InputText("Dynamic", dyn_buf, dyn_buf_size,
                 ImGuiInputTextFlags_CallbackResize,
                 MyResizeCallback);

Handling TAB Completion

The ImGuiInputTextFlags_CallbackCompletion flag fires when the user presses TAB. The callback can inspect data->CursorPos and replace the buffer contents to provide completion suggestions.

int MyCompletionCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
    {
        const char* candidates[] = { "apple", "apricot", "banana" };
        // Use data->CursorPos and data->Buf to insert a match
    }
    return 0;
}

// Usage
static char buf[64] = "";
ImGui::InputText("Fruit", buf, sizeof(buf),
                 ImGuiInputTextFlags_CallbackCompletion,
                 MyCompletionCallback);

Summary

  • The InputText family in Dear ImGui forwards all callback-enabled calls to InputTextEx, which is declared in imgui_internal.h and invoked through imgui_widgets.cpp.
  • ImGuiInputTextCallbackData provides the current state, event flag, and buffer pointers to your callback function.
  • Use ImGuiInputTextFlags_CallbackResize for dynamic strings; the misc/cpp/imgui_stdlib.cpp wrapper handles std::string automatically.
  • Use ImGuiInputTextFlags_CallbackCharFilter to reject or mutate characters before they enter the buffer.
  • Use ImGuiInputTextFlags_CallbackCompletion and ImGuiInputTextFlags_CallbackHistory for IDE-style TAB completion and arrow-key navigation.
  • Internal backup state in ImGuiInputTextState ensures undo and redo safety when callbacks modify the text.

Frequently Asked Questions

What is the difference between CallbackAlways and CallbackEdit?

ImGuiInputTextFlags_CallbackAlways invokes your callback on every frame while the widget remains active, whereas ImGuiInputTextFlags_CallbackEdit fires only after an actual edit occurs. Both mechanisms rely on the temporary backup buffer inside ImGuiInputTextState to preserve undo and redo history if you modify the text.

How do I use std::string with ImGui::InputText without writing a callback manually?

Include misc/cpp/imgui_stdlib.h and pass a pointer to your std::string directly to ImGui::InputText. The helper wrapper defined in misc/cpp/imgui_stdlib.cpp automatically supplies the ImGuiInputTextFlags_CallbackResize flag and a local callback that expands the string capacity when the internal character buffer overflows.

Can I combine multiple callback behaviors in one InputText call?

Yes. Because InputTextEx tests the flag field with bitwise AND (flags & ImGuiInputTextFlags_Callback*), multiple behaviors can be requested simultaneously by combining the corresponding enum values. The callback should inspect data->EventFlag inside its handler to distinguish which event is currently being processed.

Why must my resize callback update data->Buf directly?

When InputTextEx triggers a ImGuiInputTextFlags_CallbackResize event, it sets the required size on the ImGuiInputTextCallbackData object and expects your callback to reallocate memory and assign the new pointer to data->Buf. The widget does not perform the allocation itself; it only reads back the pointer and size you provide, which is why the raw C buffer example uses realloc to grow the heap block.

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 →