> Wouldn't it be possible to separate the public API from the internal implementation so much that the library appears "immediate mode" on the outside, but is completely "retained mode" on the inside?
It is possible but you would need some severe API changes... you could either ask the users to use unique names for each widget, or something similar like storing references between frames. Alternatively you'd have to force "same order between frames" (similar to React does with Hooks).
I think the "virtual DOM" approach is more relevant part of React to look at to answer the question. The UI code appears immediate but on each invocation builds a data structure that represents the layout and references to data it depends on. The library consumes this data structure, compares it to its own internal, retained representation and adjusts the latter according to any changes that might have occurred. Input is consumed by the "retained mode" GUI toolkit, which triggers the immediate mode UI to re-render with return values from widgets adjusted according to the "immediate mode" result of the input.
The difference from React would be representational. In React you explicitly build this data structure as something resembling a DOM tree and handle input by attaching callbacks to nodes, but I think this representation is just convenient for web development rather than fundamental to the approach.
You might still need a way to manage updates to the state the GUI depends on and re-render when it changes for some other reason than an input operation.
Dear ImGui already uses such "implicit" widget ids, by default it hashes the widget's label string, window title or name, with a convention to add an invisible 'identifier string' to the label string separated by a "##" (e.g. "Label##id") - for the case that the visible label string needs to change or isn't unique within the current scope. There are also separate PushID/PopID functions to manage such widget ids in "more elaborate ways".
This also has been one of my biggest gripes with "imgui" style of libraries - as the end of the day something needs to keep state somewhere, and implementations/hack can be very language/runtime oriented to avoid hacks like above, or use the hack above.
It also caught me by surprise, and would catch many others where seemingly normal controls, that just happen to have the same text would be identified with the same state, as the text (contents) are initially used to point to this state.
Interesting, I didn't knew that. I helped write a couple immediate-mode GUI some time ago, but I'm not deeply familiar with ImGui.
If this is the case, then it seems entirely possible to have an "internal retained mode", and might even help with some extra stuff like focus management and accessibility.
It is possible but you would need some severe API changes... you could either ask the users to use unique names for each widget, or something similar like storing references between frames. Alternatively you'd have to force "same order between frames" (similar to React does with Hooks).