The complexity that lives in the GUI
Another option is injecting an optional dependency without connecting the box.<p>I see OP doesn&#x27;t mention this option, but is slightly related to both option 1 (connect the box) and 3 (message bus &#x2F; event emitter). This option is similar to how OS provides an API to user space application program. For example Windows provides an API to an application to flash its window without exposing all of its state like mentioned in option 1. <a href="https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;windows&#x2F;win32&#x2F;api&#x2F;winuser&#x2F;nf-winuser-flashwindow" rel="nofollow">https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;windows&#x2F;win32&#x2F;api&#x2F;winuser&#x2F;n...</a><p>Here&#x27;s the detail:<p>A self-powered object, let&#x27;s call it workingIndicatorObject, can be introduced to work on the working indicator. It provides 1.) `getState() -&gt; WORKING&#x2F;NOT-WORKING` a function to get its state, and 2.) `register() -&gt; None`, a function to register user activities. These functions are dependencies for UserSection component and InventoryTable component respectively. In term of lifetime and hierarchy, it precedes and outlives both components.<p>The workingIndicatorObject MUST have its own lifecycle to regulate its internal state. Its core lifecycle MUST NOT be managed under the same event loop as the GUI components, assuming the program is written on top of a framework that has it (React, Vue, etc). This is to assure that it doesn&#x27;t directly affect the components managed by the framework (loose coupling). Although, a binding MAY be made between its state and the framework-managed event loop, for example, in React environment, wrapping it as a React hook. An EventEmitter can also be provided for a component to listen to its internal event loop.<p>Injecting it as a dependency can use features like React Context or Vue&#x27;s Provide&#x2F;Inject pattern. Its consumer must treat it as an optional dependency for it to be safe. For example, the UserSection component can omit drawing the &quot;working&quot; indicator if it doesn&#x27;t receive the `getState` function as a dependency.<p>Internally, the workingIndicatorObject can use a set. The set is used to store a unique value (a Symbol in Javascript). `register` function creates a Symbol, stores it in the set, and deletes it after $TIMEOUT, while firing event both at addition and deletion. `getState` function is a function that returns `set.size()`. When bound to the component, an addition to the set fires an &quot;update&quot; command to the component, which redraw the component along its internal state. This is just one example of implementation and there are other simpler ways to have the same behaving workingIndicatorObject.<p>This approach allows UserSection and InventoryTable to only know `getState()` and `register()` function and nothing else, and having both of them optional. Using static type system such as TypeScript can help a lot in this since we can pin down the signatures of both function to `null | () =&gt; WORKING | NOT_WORKING` and `null | () =&gt; void`, where we can enforce both dependent components to check if it exists and to call it with the correct types, otherwise the compiler yells.