Using Input Text Callbacks for Validation and Custom Processing in Dear ImGui

Dear ImGui’s input text callbacks allow you to intercept, filter, and transform user input in real-time by implementing a custom function that receives an ImGuiInputTextCallbackData structure and returns 0 to accept changes or a non-zero value to reject them.

The ocornut/imgui repository provides a sophisticated callback mechanism for the InputText() widget that enables immediate validation and custom processing without requiring post-validation loops. By specifying flags when calling ImGui::InputText(), you can register a callback function that inspects and manipulates buffer contents during specific lifecycle events, keeping UI logic tight and performant.

How Input Text Callbacks Work in Dear ImGui

The callback system centers on two core declarations in imgui.h (around line 2658): the ImGuiInputTextCallback function pointer type and the ImGuiInputTextCallbackData structure. When you invoke ImGui::InputText() with specific flags, Dear ImGui dispatches events to your callback function, passing a mutable pointer to an ImGuiInputTextCallbackData instance containing the current buffer state and event context.

Your callback must return 0 to indicate success, or a negative value to abort the input operation entirely. For character filtering specifically, returning any non-zero value discards the candidate character.

Callback Flags and Event Types

You combine the following flags to determine when your callback executes:

  • ImGuiInputTextFlags_CallbackCharFilter – Invoked for each typed character before it enters the buffer. Return non-zero to reject the character or replace EventChar to substitute it.
  • ImGuiInputTextFlags_CallbackResize – Triggered when text exceeds the current buffer capacity, allowing dynamic reallocation.
  • ImGuiInputTextFlags_CallbackEdit – Called after any insertion, deletion, or paste operation completes. Ideal for validation or formatting transformations.
  • ImGuiInputTextFlags_CallbackAlways – Executed on every frame the widget remains active, regardless of whether editing occurred.

The ImGuiInputTextCallbackData Structure

The data structure passed to your callback provides comprehensive context for manipulation:

Member Purpose
Buf Pointer to the mutable text buffer (including the terminating \0).
BufTextLen Current length of the text in bytes, excluding the null terminator.
BufSize Total allocated capacity of the buffer.
Flags The ImGuiInputTextFlags originally passed to InputText().
EventFlag Specific flag indicating why the callback was triggered (CallbackCharFilter, CallbackEdit, etc.).
EventChar The character code for CallbackCharFilter events.
EventKey The key index for keyboard-related events.
DeleteChars(), InsertChars() Helper functions to modify buffer contents programmatically during CallbackEdit.

Practical Code Examples for Input Validation

Filtering Numeric Input with CallbackCharFilter

To restrict input to digits only, inspect EventChar during CallbackCharFilter events and return 1 to reject non-numeric characters:

int MyNumericCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter)
    {
        if (!isdigit((unsigned char)data->EventChar))
            return 1;  // Discard non-digit characters
    }
    return 0;
}

// Usage
static char buf[64] = "";
ImGui::InputText("##num", buf, IM_ARRAYSIZE(buf),
                 ImGuiInputTextFlags_CallbackCharFilter,
                 MyNumericCallback);

Automatic Text Transformation with CallbackEdit

Use the edit callback to enforce formatting rules, such as converting all text to uppercase after each modification:

int UppercaseCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
    {
        for (int i = 0; i < data->BufTextLen; ++i)
            data->Buf[i] = (char)toupper((unsigned char)data->Buf[i]);
    }
    return 0;
}

// Usage
static char name[128] = "";
ImGui::InputText("##name", name, IM_ARRAYSIZE(name),
                 ImGuiInputTextFlags_CallbackEdit,
                 UppercaseCallback);

Dynamic Buffer Resizing with CallbackResize

For inputs with unknown maximum length, implement a resize callback to reallocate memory when the user exceeds the current buffer capacity:

int ResizeCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
    {
        size_t new_size = data->BufSize;
        char* new_buf = (char*)malloc(new_size);
        memcpy(new_buf, data->Buf, data->BufTextLen);
        new_buf[data->BufTextLen] = '\0';
        data->Buf = new_buf;  // ImGui adopts this new pointer
    }
    return 0;
}

// Usage with heap-allocated buffer
char* dynamic_buf = (char*)malloc(128);
dynamic_buf[0] = '\0';
ImGui::InputTextMultiline("##dyn", dynamic_buf, 128,
                          ImVec2(0,0),
                          ImGuiInputTextFlags_CallbackResize,
                          ResizeCallback);

Complex Validation: Character Filtering and Length Constraints

Combine multiple validation rules within a single callback to enforce both content type and length restrictions:

int NumericAndLengthCallback(ImGuiInputTextCallbackData* data)
{
    if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter)
    {
        if (!isdigit((unsigned char)data->EventChar))
            return 1;  // Reject non-digits
        if (data->BufTextLen >= 5)
            return 1;  // Enforce maximum length of 5 characters
    }
    return 0;
}

// Usage
static char pin[8] = "";
ImGui::InputText("##pin", pin, IM_ARRAYSIZE(pin),
                 ImGuiInputTextFlags_CharsDecimal |
                 ImGuiInputTextFlags_CallbackCharFilter,
                 NumericAndLengthCallback);

Core Implementation Files

Understanding where these mechanisms reside helps when debugging or extending functionality:

  • imgui.h – Declares ImGuiInputTextCallback, ImGuiInputTextCallbackData, and all related flags.
  • imgui.cpp – Contains the InputText() widget implementation and the dispatch logic that invokes your callbacks based on the active EventFlag.
  • misc/cpp/imgui_stdlib.cpp – Provides std::string overloads that handle CallbackResize automatically, eliminating the need for manual memory management when using C++ strings.

Summary

  • Input text callbacks in Dear ImGui provide real-time interception of user input through the ImGuiInputTextCallback function pointer and ImGuiInputTextCallbackData structure.
  • Four distinct flags control callback timing: CallbackCharFilter for per-character filtering, CallbackEdit for post-modification processing, CallbackResize for dynamic memory management, and CallbackAlways for per-frame updates.
  • Return values determine flow: return 0 to proceed, non-zero for CallbackCharFilter to discard characters, or negative values to abort the widget entirely.
  • Buffer manipulation occurs through direct pointer access (Buf) or helper methods (InsertChars, DeleteChars) within imgui.h’s callback data structure.

Frequently Asked Questions

How do I reject specific characters in ImGui::InputText?

Implement a CallbackCharFilter callback and inspect the EventChar member of the ImGuiInputTextCallbackData structure. Return any non-zero value (typically 1) to discard the character, or modify EventChar to substitute a different character before it enters the buffer.

Can I use std::string with input text callbacks instead of raw char buffers?

Yes. Include misc/cpp/imgui_stdlib.h and use the InputText overloads that accept std::string references. These implementations automatically handle the CallbackResize event by resizing the underlying string, eliminating the need for manual memory management in your callback code.

What is the difference between CallbackEdit and CallbackAlways?

CallbackEdit fires only after the buffer content actually changes due to insertion, deletion, or paste operations, making it efficient for validation and formatting. CallbackAlways executes on every frame while the widget is active, regardless of whether editing occurred, which is useful for implementing time-dependent features or continuous validation checks.

How do I enforce a maximum input length when using callbacks?

Check the BufTextLen member during CallbackCharFilter events and return non-zero if the current length already meets your limit. This prevents additional characters from entering the buffer. Alternatively, use the built-in ImGuiInputTextFlags_CharsDecimal or ImGuiInputTextFlags_CharsHexadecimal flags for common cases, and reserve the callback for custom business logic.

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 →