# How to Create Custom ImGui Widgets Using `imgui_internal.h`

> Learn to create custom IMGUI widgets using imgui_internal.h. Leverage low-level features for unique UI elements while staying compatible with the immediate-mode pipeline.

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

---

**Dear ImGui's internal header ([`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)) exposes low-level structures, flags, and helper functions that enable you to build bespoke widgets by leveraging state storage, custom rectangles, and internal API entry points while maintaining compatibility with the immediate-mode rendering pipeline.**

Dear ImGui (ocornut/imgui) provides a robust immediate-mode GUI framework for C++, but sophisticated applications often require controls beyond the standard library offerings. By tapping into the internal machinery defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h), you can extend the library with custom combos, specialized drag-drop targets, and novel interaction patterns while maintaining the library's core architectural principles.

## Core Components in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)

The internal header organizes functionality into logical sections that directly support widget extension. Understanding these compartments is essential for writing safe, compatible custom controls.

### Widget Flags and Enums

The internal API defines extended flag bits that augment public enumerations. For example, `ImGuiComboFlags_CustomPreview` allows you to override the default preview rendering of combo boxes. These flag definitions reside in the *Widgets support* section around line 1090, providing the bitwise markers necessary to signal specialized behavior to ImGui's internal state machine.

### State Storage and Context

Custom widgets require temporary state persistence across frames. The internal header exposes members like `BeginComboDepth` and functions such as `BeginComboPreview()` and `EndComboPreview()` within the *Widgets support* section (lines 2535-3533). These mechanisms allow you to store per-widget data—such as preview rectangle dimensions—without polluting the public API.

### Custom Rectangle Hit-Testing

When building widgets that don't conform to standard item boundaries, you need precise control over hit-testing regions. The `BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)` function, declared in the *Inputs support* section at line 3661, registers arbitrary bounding boxes as valid interaction targets. This is crucial for "in-place" widgets or drop zones that overlay existing content.

### Geometric Helper Structures

The header provides foundational math utilities at lines 889-925, including `ImRect` for axis-aligned bounding boxes, `ImBitVector` for efficient boolean storage, and `ImSpan<>` for memory-safe array views. These structures form the geometric backbone of custom widget implementations.

### Internal API Entry Points

The *ImGui internal API* section (lines 389-400) declares functions prefixed with `ImGui::` that bypass public safety checks. These entry points allow direct manipulation of window draw lists, ID stacks, and item state data, but require strict adherence to ImGui's internal patterns to avoid clipping errors or state corruption.

## The Custom Widget Workflow

Building a custom widget follows a predictable pattern that mirrors ImGui's internal architecture:

1. **Define a unique ID** using `ImGui::GetID()` or hash-based generation with `ImHashStr` to ensure the widget integrates with ImGui's navigation and focus systems.
2. **Create a hit-box** by constructing an `ImRect` that encompasses your widget's interactive area.
3. **Register the hit-box** with `BeginDragDropTargetCustom(bb, id)` or similar custom registration functions to enable input processing.
4. **Render geometry** using `ImDrawList` methods like `AddRectFilled()` and `AddText()` to paint your widget's appearance.
5. **Query interaction state** via `ImGui::IsItemHovered()`, `IsItemActive()`, or custom flag checks to determine user input.
6. **Cleanup state** by calling corresponding end-functions (e.g., `EndComboPreview()`) to restore internal context.

Because these calls bypass higher-level safety checks, you must manually replicate ImGui's internal state-machine patterns: pushing IDs onto the stack, adding items to the window's draw list, and updating `LastItemData` to maintain consistent clipping and navigation behavior.

## Practical Implementation Examples

The following examples demonstrate concrete usage of the internal API for common customization scenarios.

### Custom Combo Preview

This implementation uses `ImGuiComboFlags_CustomPreview` to render a bespoke preview area within a standard combo box:

```cpp
bool MyCombo(const char* label, const char* preview_text, const std::vector<const char*>& items)
{
    // 1️⃣ Create a unique ID for the combo
    ImGuiID combo_id = ImGui::GetID(label);

    // 2️⃣ Begin the combo with the custom flag
    if (!ImGui::BeginCombo(label, preview_text,
                           ImGuiComboFlags_CustomPreview))
        return false;        // Combo not opened → nothing to do

    // 3️⃣ Custom preview area – we render our own preview inside the combo button
    ImGui::BeginComboPreview();                     // ← internal call (lines 1187-1189)
    ImGui::GetWindowDrawList()->AddRectFilled(
        ImGui::GetItemRectMin(), ImGui::GetItemRectMax(),
        IM_COL32(30, 30, 80, 255));
    ImGui::GetWindowDrawList()->AddText(
        ImGui::GetItemRectMin() + ImVec2(4, 4),
        IM_COL32(255, 255, 255, 255), preview_text);
    ImGui::EndComboPreview();                       // ← internal cleanup

    // 4️⃣ List the selectable items
    for (int i = 0; i < (int)items.size(); ++i)
    {
        const bool selected = (preview_text == items[i]);
        if (ImGui::Selectable(items[i], selected))
        {
            // User selected a new entry → update preview (outside this function)
            // Return true to signal the caller to replace the preview string.
            ImGui::EndCombo();
            return true;
        }
    }
    ImGui::EndCombo();
    return false;
}

```

The critical internal calls `BeginComboPreview()` and `EndComboPreview()` are declared in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) at lines 1187-1189, allowing you to inject custom rendering between the combo header and its dropdown list.

### Custom Drag-Drop Target

This example creates a non-standard drop zone using `BeginDragDropTargetCustom()`:

```cpp
bool MyCustomDropTarget(const ImRect& rect, ImGuiID custom_id)
{
    // 1️⃣ Tell ImGui that this rectangle can be a drag‑drop target
    if (!ImGui::BeginDragDropTargetCustom(rect, custom_id))  // ← line 3661
        return false;        // No payload hovering this rect

    // 2️⃣ Accept a payload of a user‑defined type
    const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_CUSTOM_TYPE");
    if (payload)
    {
        // Payload data is available in payload->Data (raw bytes)
        // Here we just print the size for demonstration
        printf("Dropped payload size: %zu bytes\n", payload->DataSize);
        ImGui::EndDragDropTarget();               // ← internal cleanup
        return true;
    }
    ImGui::EndDragDropTarget();
    return false;
}

```

This pattern—**declare the custom area → register it with the internal API → draw → query interaction → clean up**—applies to all widgets built against [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h).

## Essential Files for Custom Widget Development

When extending ImGui, these source files provide the necessary definitions and reference implementations:

- **[`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)** — Central definition of internal flags, helper structs (`ImRect`, `ImBitVector`), and the low‑level functions (`BeginComboPreview`, `BeginDragDropTargetCustom`) required for custom widget construction.
- **[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)** — The public façade that forwards to the internal API; contains the public enums (`ImGuiComboFlags`) that you extend with internal flag bits.
- **[`imconfig.h`](https://github.com/ocornut/imgui/blob/main/imconfig.h)** (optional) — User configuration file where you can define `IMGUI_INCLUDE_IMGUI_INTERNAL_H` or customize compile-time behavior.
- **[`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp)** — Reference implementations showing concrete widget patterns; useful as a template when adapting internal calls.

## Summary

- **[`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)** exposes low-level API functions, geometric helpers (`ImRect`, `ImSpan`), and extended flags (`ImGuiComboFlags_CustomPreview`) necessary for custom widget creation.
- **Custom widgets require explicit state management**: you must manually handle ID generation, hit-box registration via `BeginDragDropTargetCustom()`, and cleanup via corresponding end-functions.
- **The internal API bypasses safety checks**, requiring strict adherence to ImGui's state-machine patterns (pushing IDs, updating `LastItemData`, managing draw lists) to prevent rendering artifacts.
- **Key functions** like `BeginComboPreview()` (lines 1187-1189) and `BeginDragDropTargetCustom()` (line 3661) enable specialized rendering and input handling without modifying the core library.
- **Workflow consistency** follows the pattern: define ID → create `ImRect` → register with internal API → render → query state → cleanup.

## Frequently Asked Questions

### What is the difference between [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) and [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)?

[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) provides the stable public API with guaranteed backward compatibility, while [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) exposes implementation details that may change between versions. The internal header contains the low-level structures and functions—such as `ImRect` helpers and `BeginDragDropTargetCustom()`—that widget developers need to access ImGui's internal state machinery.

### Is it safe to use the internal API in production code?

Using [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) requires accepting that function signatures and behavior may change in future releases. However, the internal API is remarkably stable in practice, and many production applications rely on it for custom widgets. To minimize breakage, pin your project to specific ImGui versions or wrap internal calls in abstraction layers that you can update when upgrading.

### How do I handle ID conflicts when creating custom widgets?

Always generate unique IDs using `ImGui::GetID(label)` or `ImHashStr()` combined with your widget's label and optional index parameters. When building composite widgets (containers with multiple interactive elements), explicitly push and pop ID scopes using `ImGui::PushID()` and `ImGui::PopID()` to ensure child elements don't collide with sibling widgets or other windows.

### Can I use the internal API with Dear ImGui's docking and multi-viewport features?

Yes, the internal API fully supports advanced features like docking and multi-viewport rendering. When using `BeginDragDropTargetCustom()` or similar functions, ensure your `ImRect` coordinates are in the correct window space, and always pair internal begin/end calls within the same window context to maintain proper clip rect and viewport synchronization.