Based on this experience I have a compiled a list of basic rules for a component to follow.
A well behaved component should be an instantiable object that exposes an API, which will enable the parent application to completely control that single instance of that component.
Unless instructed to by the parent application, the component should never search through, read from or write to the DOM.
When the component wants to inform the parent application of an event prefer to do so via the observer pattern. One very light, NPM/bower installable event library is Wilson Page’s event.
To avoid detached DOM nodes, it should leave no event listener bound to any DOM element (even if that DOM element has gone).
It should be able to cope with being instantiated multiple times. It, and none of its sub-components (or sub-sub-components, etc) should be singletons.
Similarly if the component is dependent on some CSS, it should expose a route to that CSS (either as pure text or a via URL) and the parent application should be responsible injecting or importing those style rules.
It should expect that it can be destroyed at any time. All callbacks to asynchronous logic should handle the case where the objects or DOM nodes that they were just talking to no longer exist.