How to Implement Custom Data Types for Sliders and Drag Controls in ImGui

Dear ImGui's generic slider and drag widgets work with any scalar type by extending the ImGuiDataType_ enum and providing a corresponding ImGuiDataTypeInfo entry that describes size, format, and conversion traits.

Dear ImGui (ocornut/imgui) provides generic scalar widgets that manipulate raw memory through type descriptors, allowing you to implement custom data types for sliders and drag controls without modifying the core widget logic. Instead of limiting sliders to built-in primitives like float or int, the library exposes SliderScalar and DragScalar functions that accept any POD type through a declarative type system defined in imgui.h and imgui.cpp.

Understanding the Type System Architecture

The extensibility lives in three coordinated components that bridge the public API and internal implementations.

The ImGuiDataType_ Enum (imgui.h)

Located at line 1515 in imgui.h, the ImGuiDataType_ enumeration declares unique integer identifiers for each supported type. When you add a custom type, you append a new entry here (e.g., ImGuiDataType_MyVec2) before ImGuiDataType_COUNT. This identifier serves as the bridge between the generic widget API and the type metadata table.

The ImGuiDataTypeInfo Table (imgui.cpp)

Around line 778 in imgui.cpp, the GetImGuiDataTypeInfo() function (backed by the static GImGuiDataTypeInfo[] table) maps each enum value to an ImGuiDataTypeInfo struct. This metadata supplies the widget code with:

  • Size: Byte size of the type (sizeof(MyVec2))
  • PrintFmt: Default format string for text rendering (e.g., "%0.2f")
  • IsIntegral and IsFloatingPoint: Classification flags that determine clamping behavior

Generic Widget Implementation (imgui_widgets.cpp)

The SliderScalar implementation in imgui_widgets.cpp (around line 3316) and the DragScalar functions treat the data pointer as opaque raw memory. They delegate bounds checking and interaction handling to SliderBehavior and DragBehavior, using the type metadata to perform clamping and string formatting without knowing the concrete C++ type.

Step-by-Step Implementation

Follow these steps to expose a new data type to the slider and drag controls.

Step 1: Extend the ImGuiDataType_ Enum

Add your custom type identifier to the enum in imgui.h:

enum ImGuiDataType_
{
    // ... existing entries like ImGuiDataType_Float, ImGuiDataType_S32 ...
    ImGuiDataType_MyVec2,       // Custom 2D vector
    ImGuiDataType_MyBlendMode,  // Custom enum
    ImGuiDataType_COUNT
};

Step 2: Define Type Metadata in ImGuiDataTypeInfo

Register the type characteristics in imgui.cpp within the GImGuiDataTypeInfo array:

static const ImGuiDataTypeInfo GImGuiDataTypeInfo[] =
{
    // ... existing entries ...
    { sizeof(MyVec2),     "%0.2f", false, false }, // MyVec2 - treated as floating point
    { sizeof(int),        "%d",    true,  false }  // MyBlendMode - stored as int
};

Step 3: Use SliderScalar and DragScalar with Custom Types

Call the generic widgets with your new type identifier:

MyVec2 v = {0.5f, 0.25f};
MyVec2 v_min = {0.0f, 0.0f};
MyVec2 v_max = {1.0f, 1.0f};

ImGui::SliderScalar("MyVec2", ImGuiDataType_MyVec2, &v, &v_min, &v_max, "%.2f");

Practical Code Examples

Below is a complete implementation showing a custom vector struct and enum working with the generic widget API.

// ------------------------------------------------------------
// 1. Define custom types
// ------------------------------------------------------------
struct MyVec2 { float x, y; };
enum class MyBlendMode : int { Opaque = 0, Transparent = 1, Additive = 2 };

// ------------------------------------------------------------
// 2. Extend ImGuiDataType_ (in imgui.h)
// ------------------------------------------------------------
enum ImGuiDataType_
{
    // ... existing entries ...
    ImGuiDataType_MyVec2,          // Custom type 1
    ImGuiDataType_MyBlendMode,    // Custom type 2
    ImGuiDataType_COUNT
};

// ------------------------------------------------------------
// 3. Add DataTypeInfo entries (in imgui.cpp)
// ------------------------------------------------------------
static const ImGuiDataTypeInfo GImGuiDataTypeInfo[] =
{
    // ... existing entries ...
    { sizeof(MyVec2),      "%0.2f",  false, false }, // MyVec2
    { sizeof(int),        "%d",    true,  false }   // MyBlendMode (int-based)
};

// ------------------------------------------------------------
// 4. Use the generic widgets
// ------------------------------------------------------------
void ShowCustomWidgets()
{
    static MyVec2    v = { 0.5f, 0.25f };
    static MyVec2    v_min = { 0.0f, 0.0f };
    static MyVec2    v_max = { 1.0f, 1.0f };
    static MyBlendMode mode = MyBlendMode::Opaque;
    static int       mode_min = 0;
    static int       mode_max = 2;

    // Slider for the whole vector (2 components)
    ImGui::SliderScalarN("MyVec2", ImGuiDataType_MyVec2, &v, 2,
                         &v_min, &v_max, "%.2f");

    // Drag control for a single component
    ImGui::DragScalar("MyVec2 X", ImGuiDataType_Float, &v.x, 0.01f,
                      &v_min.x, &v_max.x, "%.3f");

    // Slider for the custom enum using integer representation
    ImGui::SliderScalar("Blend Mode", ImGuiDataType_MyBlendMode,
                        &mode, &mode_min, &mode_max, "%d");
    
    // Display human-readable label
    const char* mode_names[] = { "Opaque", "Transparent", "Additive" };
    ImGui::SameLine(); 
    ImGui::Text("(%s)", mode_names[(int)mode]);
}

Working with Multi-Component Types

For vector types containing multiple scalars, use SliderScalarN or DragScalarN as shown in the example above. These functions treat the data pointer as an array of the specified type, iterating through components elements. When operating on a MyVec2 with components=2, the widget applies the same min/max bounds to each float within the struct sequentially.

Since the widget operates on raw memory, you can also wrap existing types by creating a thin struct containing a single scalar value and exposing it via a custom ImGuiDataType_ entry. The widget reads and writes the underlying bytes transparently, allowing you to impose semantic meaning on standard primitives without changing the rendering logic.

Summary

  • Extend ImGuiDataType_ in imgui.h to declare your custom type identifier before ImGuiDataType_COUNT
  • Populate ImGuiDataTypeInfo in imgui.cpp with size, format string, and type classification flags (IsIntegral, IsFloatingPoint)
  • Use SliderScalar, DragScalar, SliderScalarN, or DragScalarN with your new type enum and appropriate min/max pointers
  • The generic widgets in imgui_widgets.cpp handle clamping via SliderBehavior and DragBehavior using the raw memory description
  • Multi-component types work transparently with the ...ScalarN variants that iterate over contiguous memory blocks

Frequently Asked Questions

Can I implement custom data types without modifying Dear ImGui's source code?

Currently, extending ImGuiDataType_ and ImGuiDataTypeInfo requires modifying imgui.h and imgui.cpp because the type table is static and indexed by the enum. However, you can work around this limitation by treating your custom type as a supported underlying type (like float or int) and handling the conversion manually in your application code before calling the widget.

How does SliderScalar handle bounds checking for custom structs?

The SliderBehavior function performs bounds checking using raw memory comparisons based on the Size field from ImGuiDataTypeInfo. For multi-component types like MyVec2, the widget treats each component as an independent scalar when using SliderScalarN, applying the min/max values to each float within the struct. The widget clamps values by comparing the underlying bytes as if they were the specified scalar type.

What format strings work with custom types in DragScalar?

The PrintFmt field in your ImGuiDataTypeInfo entry determines the default formatting, but you can override this by passing a custom format string as the final parameter to DragScalar or SliderScalar. For integer-based enums, use "%d"; for floating-point vectors, use "%.2f" or similar precision specifiers. The format string follows standard printf conventions compatible with the underlying scalar representation.

Why does my custom type slider show incorrect values or corrupt memory?

Ensure the Size field in your ImGuiDataTypeInfo entry exactly matches sizeof(YourType) and that the IsFloatingPoint or IsIntegral flags correctly reflect the underlying representation. Mismatched sizes cause the widget to read incorrect memory offsets, while incorrect type flags affect the formatting logic and clamping behavior. Verify that your custom type is a POD (Plain Old Data) struct without virtual functions or complex constructors.

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 →