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
InputTextfamily in Dear ImGui forwards all callback-enabled calls toInputTextEx, which is declared inimgui_internal.hand invoked throughimgui_widgets.cpp. ImGuiInputTextCallbackDataprovides the current state, event flag, and buffer pointers to your callback function.- Use
ImGuiInputTextFlags_CallbackResizefor dynamic strings; themisc/cpp/imgui_stdlib.cppwrapper handlesstd::stringautomatically. - Use
ImGuiInputTextFlags_CallbackCharFilterto reject or mutate characters before they enter the buffer. - Use
ImGuiInputTextFlags_CallbackCompletionandImGuiInputTextFlags_CallbackHistoryfor IDE-style TAB completion and arrow-key navigation. - Internal backup state in
ImGuiInputTextStateensures 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →