Why IDs Matter
Dear ImGui needs to uniquely identify UI elements internally to:- Track active widgets (which slider is being dragged)
- Track focus state (which input field has keyboard focus)
- Remember window state (position, size, collapsed state)
- Remember tree node state (which nodes are open/closed)
- Associate temporary state with widgets
Non-interactive widgets like
Text() don’t need IDs. Interactive widgets like Button(), SliderFloat(), InputText() etc. all need unique IDs.How IDs Are Generated
IDs are hashed from a stack of identifiers that forms a “path” to each widget:The Most Common Mistake
Solution 1: Unique Labels
Use different labels:Solution 2: The ## Operator
Use## to add a hidden unique suffix:
## and everything after it is used for the ID but not displayed.
Creating Hidden Widgets
Solution 3: PushID() / PopID()
The most powerful and flexible approach - add custom ID components to the stack:- Iteration 0:
hash("Window", 0, "Position"),hash("Window", 0, "Color") - Iteration 1:
hash("Window", 1, "Position"),hash("Window", 1, "Color") - Iteration 2:
hash("Window", 2, "Position"),hash("Window", 2, "Color")
PushID() Variants
You can push different types:Example: Object List
Nested ID Scopes
You can nestPushID() calls:
Tree Nodes and ID Stack
Tree nodes automatically push an ID when opened:The ### Operator
Use### to change the label while keeping the same ID:
### is the label. Everything after (including ###) is used for the ID:
Empty Labels
Debugging ID Conflicts
Dear ImGui provides tools to debug ID issues:ID Stack Tool Window
- The current ID stack path
- The hash value at each level
- Which widget corresponds to which ID
Using the Demo
Common Patterns
Pattern 1: Dynamic Lists
Pattern 2: Property Grids
Pattern 3: Tabs/Pages
Advanced: Manual ID Management
GetID() Function
You can manually compute IDs:Comparing IDs
ID Stack Rules Summary
Quick Reference
Quick Reference
- Always use unique labels in the same scope
- Use
##hidden_idfor unique IDs with same visible label - Use
###persistent_idfor dynamic labels with stable IDs - Use
PushID()/PopID()when iterating or creating dynamic UI - Never use empty labels without
## - Windows automatically push their name to the ID stack
- Tree nodes automatically push their label when open
- Always pair
PushID()withPopID()
Window IDs and .ini Files
Window IDs affect saved settings:Performance Considerations
ID hashing is very fast. Don’t worry about performance when using
PushID():- Integer hash: ~1-2 CPU cycles
- String hash: ~2-3 cycles per character
- Pointer hash: ~1-2 CPU cycles
Common Errors and Fixes
Error: “Widget not responding to clicks”
Cause: ID conflict - another widget has the same ID Fix: Use unique labels orPushID()
Error: “Wrong widget is activated”
Cause: Multiple widgets share the same ID Fix: Add##unique_suffix or use PushID()
Error: “Tree node state not saved”
Cause: Tree node ID changes each frame Fix: Use###persistent_id for dynamic tree labels
Error: “Window position not saved”
Cause: Window name changes each frame Fix: Use###WindowID for dynamic window titles
Next Steps
- Learn about Input Handling to understand how IDs relate to input routing
- Explore Widgets to see ID usage in practice
- Check the Troubleshooting Guide for more common questions