You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Modern interfaces frequently need to hide a part of the UI without treating that UI as gone.
Tab is switched away from, but the user expects its form input to remain. Previously visited route is left, but returning should restore the exact local state. A complex editor is temporarily hidden, but recreating it from scratch is unnecessarily expensive. Screen that is likely to be visited next may be worth preparing before the user asks for it.
Today, Solid does not expose a first-class abstraction for this class of behavior.
The usual conditional rendering pattern expresses only one semantic operation:
<Showwhen={visible()}><Panel/></Show>
When the condition becomes false, the subtree is disposed. Its local reactive state and DOM are gone.
The obvious alternative is to keep the subtree mounted and hide it with CSS:
This preserves the subtree, but does not express that the UI is no longer active. Reactive computations, effects, subscriptions, timers, and other work may continue running.
There is therefore a gap between:
visible and active
and:
destroyed
This proposal explores whether Solid should introduce a third concept:
retained but not currently visible
The tentative name for a user-facing primitive is:
<Activity><Panel/></Activity>
The purpose of this RFC is not to prescribe a final API or implementation.
In particular, this RFC intentionally does not decide yet:
whether inactive content should continue reacting;
whether Effects should be disposed or paused;
whether DOM should remain in place or be relocated;
whether asynchronous computations should continue;
whether the primitive should be called Activity, KeepAlive, or something else;
whether retention should include automatic eviction;
how SSR and hydration should interact with the concept.
The goal is to establish the problem, examine prior art, and identify the semantics that a Solid-native solution would need to provide.
1. The problem
UI has more than two meaningful lifetime states
Most UI code implicitly treats a subtree as either: present or gone
But many interactions require a third state: present, but temporarily inactive (fill the different)
When the user switches from Profile to Settings, Profile is no longer needed at this moment.
But that does not necessarily mean - destroy everything associated with Profile.
The user may expect:
entered form values to remain;
scroll position to remain;
an expanded subsection to remain expanded;
a video to remain at its previous position;
an expensive editor not to be rebuilt;
previously loaded data to remain available.
The distinction is therefore: not visible VS no longer needed, those are not equivalent states.
2. Why this matters in Solid
Solid's ordinary conditional rendering is intentionally efficient. Component that is no longer needed should be disposed rather than kept alive indefinitely. That is exactly what makes this pattern valuable:
<Showwhen={condition()}><Panel/></Show>
It is not a mistake, it expresses:
If this branch does not exist, destroy it.
The problem is that there is no equally direct way to express the opposite:
This branch is temporarily not visible, but I still want to retain it.
The current userland solutions therefore tend to simulate retention by manually keeping ownership and DOM around. The uploaded draft surveys several such implementations in the Solid ecosystem. This suggests that the problem is not merely theoretical. But multiple userland implementations are only evidence that the use case exists. They do not by themselves prove that a particular core API or lifecycle model is correct. That distinction is important for this RFC.
3. Simple spectrum of UI lifetime
Very useful starting point is to stop thinking in terms of “mounted versus unmounted” and instead consider a spectrum:
The first and last states are already well understood. The middle state is where this proposal begins. We can describe the three states informally as:
Visible
The UI is currently presented to the user.
Retained but inactive
The UI is not currently presented, but the application intends to be able to restore it without recreating it from nothing.
Destroyed
The UI and its associated runtime state have been released.
This RFC argues that the middle state is useful enough to deserve a first-class representation.
4. Less obvious use cases
The importance of preserving the user interface subtree is not limited to interfaces with tabs or multi-step forms. This is partly because, from a performance standpoint, it is sometimes easier to recreate the subtree than to cache it in one form or another. In many applications, this need manifests indirectly: the user expects an object to remain the same, even if it is temporarily outside the visible interaction area.
These cases are particularly useful because they highlight requirements that are easy to overlook if you view an Activity solely as a “tab-preservation” feature.
4.1. Long-lived media and embedded documents
Consider an application with an embedded document or media surface:
The user temporarily switches to another part of the interface. The question is not simply whether application state survives. The embedded document itself has state that may be owned by the browser rather than Solid:
playback position;
iframe browsing state;
text selection;
scroll position;
internal document state.
Recreating the subtree may therefore destroy information that the application never explicitly modeled as state.
A retained subtree provides a way to preserve the identity of the browser-managed resource itself.
This is an important distinction:
application state ≠ DOM/browser state
Framework-level retention primitive can preserve both without requiring the application to manually serialize every piece of transient browser state.
4.2. Interruptible workflows
Some interfaces allow an operation to be temporarily interrupted without being cancelled, for example:
User is editing an object ~> opens a command palette / inspector / side workflow ~> performs another operation ~> returns to the original object
The original UI may contain transient state that should not become part of the application's persistent model:
current text selection;
partially composed input;
expanded sections;
temporary validation state;
local undo/redo state;
cursor position.
The important property is that the workflow was interrupted, not completed or abandoned. A retention primitive gives the framework a way to represent this distinction explicitly.
4.3. Multiple simultaneous object views
Consider an application such as an IDE, design tool, CAD system, or database client. A user may have several views onto the same conceptual object:
Document A
├ editor
├ outline
└ preview
Document B
├ editor
├ outline
└ preview
Only one document may be visible at a given time. Destroying the inactive view can be surprisingly expensive because reconstructing it may require:
recreating large DOM structures;
rebuilding local component state;
restoring selections;
reconnecting integrations;
recomputing derived UI state.
Here retention becomes a form of UI object identity: view(A), continues to be the same UI object when it reappears. This is conceptually different from simply preserving application state.
4.4. Temporary loss of layout ownership
Some interfaces move content between different presentation contexts, for example, a media player may transition between:
inline player ~> picture-in-picture / overlay ~> fullscreen ~> inline player
or an inspector may move between:
right sidebar ~> floating panel ~> bottom drawer
The important property is not merely “hide this element”. The UI temporarily changes where the existing subtree participates in the interface. A retained-subtree abstraction raises the possibility of treating this as:
same UI
different presentation
rather than:
destroy UI A
create UI B
This is one reason DOM identity can matter independently of framework state.
4.5. Background preparation of expensive interaction surfaces
Suppose an application can predict the next likely interaction:
user opens a file ~> application predicts "rename" is likely ~> rename UI is prepared ~> user opens rename
A framework may want to prepare the subtree before it becomes visible:
not visible ~> initialize ~> load code/data ~> prepare UI ~> show
This is related to React's use of hidden Activity for background preparation. React documents that hidden Activities can render their content at lower priority so that code and data can be prepared before the content is shown. (react.dev)
For Solid, the interaction with the new asynchronous reactive model makes this particularly interesting:
The underlying canvas may contain substantial local UI state:
selection;
interaction mode;
hover state;
local transforms;
custom elements;
browser-managed state.
The overlay should not require the underlying surface to be reconstructed when it disappears. More importantly, an application may want the underlying surface to become temporarily inactive rather than simply invisible. This exposes the deeper distinction between: not visible and not currently participating in the interaction
4.X The number of examples is unlimited
5. What existing solutions tell us
Several frameworks already solve parts of this problem, but they do so differently. That divergence is useful because it shows that the fundamental problem is broader than any one implementation.
React defines hidden Activity as retained UI whose Effects are cleaned up while its state is preserved. Hidden descendants can still render updates at lower priority. When the Activity becomes visible, Effects are recreated. Therefore combines several ideas:
This is strong evidence that a mainstream UI system considers “hidden but retained” to be a meaningful semantic state. However, React's implementation is built around Fiber, lanes, component state, and rendering priority. Solid does not share that architecture. Therefore React gives us prior art for the problem, not necessarily the correct design.
Vue caches component instances and uses explicit activation/deactivation lifecycle hooks. It also supports bounded caches with max, allowing inactive instances to be evicted. The important conceptual difference is: component instance caching, rather than general reactive activity state This leads to a useful design question for Solid: Is the primitive fundamentally about components, or about retained reactive subtrees? Solid has no need to define the problem in terms of framework-managed component instances.
5.3. Angular RouteReuseStrategy
Angular's RouteReuseStrategy demonstrates a narrower approach. A router can decide: detach, store, reattach, destroy for a route subtree. This is valuable evidence for retention, but it is intentionally router-specific. A Solid primitive should not necessarily force the general concept into a router abstraction.
5.4. Lit
Lit also has a cache directive that preserves template instances instead of recreating them when switching between templates. This reinforces an important distinction: preserve UI identity, can be useful even when the UI is no longer visible. Again, however, DOM/template retention is not the same thing as a reactive lifecycle.
6. The fundamental design question
The previous systems suggest that the problem actually contains several independent questions.
When a subtree becomes invisible:
Should its state survive? Probably yes.
Should its DOM survive? Often yes.
Should its Effects remain active? Not necessarily.
Should it continue responding to external signals? Unknown.
Should its asynchronous computations continue? Unknown.
Should the DOM remain in its original location? Unknown.
Should hidden content be rendered in the background? Sometimes.
The critical point is that these are separate dimensions. A good Solid API should not accidentally answer all seven merely because one particular framework already did.
7. A semantic decomposition
Instead of defining Activity immediately as a component behavior, we can decompose the concept.
Does the subtree continue to exist? retained vs destroyed Visibility
Can the user currently see/interact with it? visible vs hidden Activity
Does the subtree actively perform runtime work? active vs inactive Propagation
How do changes from outside the subtree affect it? continue, delay, block, invalidate, Resource lifetime
Do subscriptions, timers and external resources remain alive? alive vs released
This immediately exposes why the problem is interesting. A single boolean called hidden may be insufficient to describe the underlying semantics.
8. Candidate semantic models
Before choosing an API, it is useful to consider possible models.
Model A - Visual retention only
state retained
DOM retained
reactivity unchanged
effects unchanged
This is approximately what developers already get from display: none It is useful, but it does not introduce a new runtime lifecycle.
Model B - Retention + effect suspension
state retained
DOM retained
effects stopped
reactivity partly active
This is closest to React Activity's public behavior.
Model C - Full reactive suspension
state retained
DOM retained
effects stopped
derived stopped
propagation stopped
The subtree becomes effectively dormant until restored.
Model D - Retention + lazy invalidation
A particularly interesting possibility for Solid is:
state retained
DOM retained
effects suspended
invalidations retained
computation deferred
Conceptually:
external signal changes ~> subtree is marked stale ~> no work is performed ~> subtree becomes visible ~> necessary computations resume
Model D - Retention + lazy invalidation
A particularly interesting possibility for Solid is:
state retained
DOM retained
effects suspended
invalidations retained
computation deferred
Conceptually: This is not a proposal to adopt that implementation. It is included because Solid's fine-grained dependency graph may make this model particularly natural. The important question is whether it is both: semantically correct, technically practical. That should be investigated rather than assumed.
9. Why Solid may have a unique opportunity
Solid's runtime already has explicit reactive ownership. A subtree is not merely a visual grouping. It has an associated ownership structure containing computations, effects and cleanup behavior. This is a materially different starting point from a Virtual DOM renderer. Solid 2 also makes asynchronous computation increasingly integrated with its reactive model rather than treating asynchronous data as a completely separate category. The current Solid 2 work therefore makes questions about retained reactive work particularly relevant. That suggests a possible Solid-native interpretation:
Whether that interpretation is actually desirable is precisely what the discussion should determine.
10. DOM preservation is a separate question
One tempting implementation is to physically move hidden DOM elsewhere. Modern browsers now expose moveBefore(), which performs a state-preserving move rather than the traditional remove-and-reinsert sequence. The DOM specification explicitly defines it as moving a node while preserving associated state. However, moveBefore() remains limited-availability and is not yet Baseline. It also imposes constraints on connected versus disconnected trees. Therefore this RFC deliberately does not define DOM relocation as part of the semantic contract. A future implementation may use: display:none, moveBefore(), renderer-specific retention depending on the renderer and browser capabilities. The semantic requirement should be: A retained subtree should not be unnecessarily recreated merely because it temporarily becomes invisible. The mechanism should remain an implementation question.
11. The strongest argument for a first-class primitive
A reasonable objection is: "Developers can already keep content mounted and hide it." That is true. But that implementation gives us only: visible vs invisible. It does not give us a framework-level concept of: visible vs retained vs destroyed
The same distinction appears independently in several ecosystems:
React ~> Activity
Vue ~> KeepAlive
Angular ~> RouteReuseStrategy
Lit ~> cache
The API shapes differ because the frameworks differ. That suggests the common denominator is not a particular API. The common denominator is the need to preserve identity across a visibility transition.
12. Why not make this purely a router problem?
Router reuse is only one instance of the problem. A tab can need retention without being a route. A modal can need retention without being a route. A complex component inside an editor can need retention without being either. A router-specific solution therefore captures only: route reuse, while the underlying problem is subtree reuse. Angular demonstrates that route retention has independent value, but its API is intentionally scoped to routing. A lower-level primitive could support routing without making routing part of the core API.
13. Why not automatically cache everything?
Because retention is not free. Keeping more UI alive means: more memory, more retained DOM, more retained state. Different frameworks therefore make different choices. Vue provides an explicit bounded cache through max. React leaves retention policy largely to the application. This RFC does not propose deciding that question yet. A first-class primitive and an automatic cache are different abstractions:
Activity
= retain this subtree
Cache
= decide which retained subtrees survive
Combining them prematurely would unnecessarily enlarge the API.
14. Why this is not simply “React Activity for Solid”
There is obvious prior art in React, and the proposed name is intentionally borrowed only tentatively. But the architectural questions differ. React answers: How should Fiber treat hidden work? Solid must answer: What should happen to an owned fine-grained reactive subtree, when its UI is temporarily inactive? React's hidden Activity still permits lower-priority updates. A Solid implementation might instead discover that: lazy invalidation is preferable or full continuation might be preferable, or a hybrid based on computation kind might be possible. The RFC should therefore avoid assuming the answer.
where VISIBLE means the subtree is currently presented. RETAINED means the subtree still exists and can be shown again without reconstruction. DESTROYED meansits lifetime has ended. This state machine is intentionally minimal. It does not yet say what the runtime should do with every signal or effect. That is a feature, not a defect.
16. Questions the Solid community needs to answer
Before finalizing any API, the following questions should be discussed.
State
What must survive a visibility transition?
signal values;
stores;
component-local variables;
DOM state;
async state;
user-created resources.
Effects
Should createEffect continue running? Should it be paused? Should it be recreated on activation?
Reactivity
If an external signal changes while the subtree is retained:
source ~> retained subtree
should the subtree:
recompute immediately;
recompute at lower priority;
be marked stale;
ignore the update until activation?
Async computations
Should async work continue? Should it be cancelled? Should its latest value be retained? Should a hidden subtree be allowed to prefetch data?
DOM
Should hidden DOM:
stay in place;
be moved;
be detached;
use renderer-specific semantics?
Composition
How should nested retained subtrees behave?
<Activity><Activity>
...
</Activity></Activity>
Routing
Can the router later build route caching on top of the primitive?
SSR
Should a retained-but-hidden subtree be rendered on the server?
Hydration
Can retained subtrees become independent hydration units?
These are possible future uses, not requirements of the initial API.
20. Non-goals
This RFC does not currently propose:
a router API;
a data-fetching API;
an LRU cache;
persistence;
state serialization;
server-side caching;
specific DOM relocation strategy;
specific scheduling algorithm;
specific async cancellation policy.
The proposal is intentionally smaller: Define whether Solid should have a first-class representation of UI that is retained across visibility changes.
21. The central proposal
The actual proposal is therefore deliberately modest: Solid should investigate a first-class abstraction for retaining a UI subtree across visibility changes. The desired transition is: VISIBLE ~> temporarily not needed ~> RETAINED ~> needed again ~> VISIBLE rather than forcing every application to choose between: destroy everything and keep everything running
22. Conclusion
The web platform and modern UI frameworks increasingly distinguish not currently visible from no longer needed. React's Activity, Vue's KeepAlive, Angular's route reuse, and Lit's caching mechanisms all address different manifestations of that distinction. Solid currently provides excellent primitives for both ends of the lifecycle: create and react, dispose. What is missing is a clearly defined intermediate semantic state: retain, but temporarily do not present. This RFC does not claim to know the correct implementation yet. It proposes that the problem itself should become an explicit part of Solid's design discussion. The next step should be to determine the semantics of that state before deciding whether the final API should be called <Activity /> or something else. The API is not the proposal. The lifecycle concept is.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Abstract
Modern interfaces frequently need to hide a part of the UI without treating that UI as gone.
Tab is switched away from, but the user expects its form input to remain. Previously visited route is left, but returning should restore the exact local state. A complex editor is temporarily hidden, but recreating it from scratch is unnecessarily expensive. Screen that is likely to be visited next may be worth preparing before the user asks for it.
Today, Solid does not expose a first-class abstraction for this class of behavior.
The usual conditional rendering pattern expresses only one semantic operation:
When the condition becomes false, the subtree is disposed. Its local reactive state and DOM are gone.
The obvious alternative is to keep the subtree mounted and hide it with CSS:
This preserves the subtree, but does not express that the UI is no longer active. Reactive computations, effects, subscriptions, timers, and other work may continue running.
There is therefore a gap between:
visible and active
and:
destroyed
This proposal explores whether Solid should introduce a third concept:
retained but not currently visible
The tentative name for a user-facing primitive is:
The purpose of this RFC is not to prescribe a final API or implementation.
In particular, this RFC intentionally does not decide yet:
whether inactive content should continue reacting;
whether Effects should be disposed or paused;
whether DOM should remain in place or be relocated;
whether asynchronous computations should continue;
whether the primitive should be called Activity, KeepAlive, or something else;
whether retention should include automatic eviction;
how SSR and hydration should interact with the concept.
The goal is to establish the problem, examine prior art, and identify the semantics that a Solid-native solution would need to provide.
1. The problem
UI has more than two meaningful lifetime states
Most UI code implicitly treats a subtree as either: present or gone
But many interactions require a third state: present, but temporarily inactive (fill the different)
Consider a tab interface:
When the user switches from Profile to Settings, Profile is no longer needed at this moment.
But that does not necessarily mean - destroy everything associated with Profile.
The user may expect:
entered form values to remain;
scroll position to remain;
an expanded subsection to remain expanded;
a video to remain at its previous position;
an expensive editor not to be rebuilt;
previously loaded data to remain available.
The distinction is therefore: not visible VS no longer needed, those are not equivalent states.
2. Why this matters in Solid
Solid's ordinary conditional rendering is intentionally efficient. Component that is no longer needed should be disposed rather than kept alive indefinitely. That is exactly what makes this pattern valuable:
It is not a mistake, it expresses:
If this branch does not exist, destroy it.
The problem is that there is no equally direct way to express the opposite:
This branch is temporarily not visible, but I still want to retain it.
The current userland solutions therefore tend to simulate retention by manually keeping ownership and DOM around. The uploaded draft surveys several such implementations in the Solid ecosystem. This suggests that the problem is not merely theoretical. But multiple userland implementations are only evidence that the use case exists. They do not by themselves prove that a particular core API or lifecycle model is correct. That distinction is important for this RFC.
3. Simple spectrum of UI lifetime
Very useful starting point is to stop thinking in terms of “mounted versus unmounted” and instead consider a spectrum:
The first and last states are already well understood. The middle state is where this proposal begins. We can describe the three states informally as:
Visible
The UI is currently presented to the user.
Retained but inactive
The UI is not currently presented, but the application intends to be able to restore it without recreating it from nothing.
Destroyed
The UI and its associated runtime state have been released.
This RFC argues that the middle state is useful enough to deserve a first-class representation.
4. Less obvious use cases
The importance of preserving the user interface subtree is not limited to interfaces with tabs or multi-step forms. This is partly because, from a performance standpoint, it is sometimes easier to recreate the subtree than to cache it in one form or another. In many applications, this need manifests indirectly: the user expects an object to remain the same, even if it is temporarily outside the visible interaction area.
These cases are particularly useful because they highlight requirements that are easy to overlook if you view an Activity solely as a “tab-preservation” feature.
4.1. Long-lived media and embedded documents
Consider an application with an embedded document or media surface:
The user temporarily switches to another part of the interface. The question is not simply whether application state survives. The embedded document itself has state that may be owned by the browser rather than Solid:
Recreating the subtree may therefore destroy information that the application never explicitly modeled as state.
A retained subtree provides a way to preserve the identity of the browser-managed resource itself.
This is an important distinction:
application state ≠ DOM/browser state
Framework-level retention primitive can preserve both without requiring the application to manually serialize every piece of transient browser state.
4.2. Interruptible workflows
Some interfaces allow an operation to be temporarily interrupted without being cancelled, for example:
The original UI may contain transient state that should not become part of the application's persistent model:
The important property is that the workflow was interrupted, not completed or abandoned. A retention primitive gives the framework a way to represent this distinction explicitly.
4.3. Multiple simultaneous object views
Consider an application such as an IDE, design tool, CAD system, or database client. A user may have several views onto the same conceptual object:
Only one document may be visible at a given time. Destroying the inactive view can be surprisingly expensive because reconstructing it may require:
Here retention becomes a form of UI object identity: view(A), continues to be the same UI object when it reappears. This is conceptually different from simply preserving application state.
4.4. Temporary loss of layout ownership
Some interfaces move content between different presentation contexts, for example, a media player may transition between:
or an inspector may move between:
The important property is not merely “hide this element”. The UI temporarily changes where the existing subtree participates in the interface. A retained-subtree abstraction raises the possibility of treating this as:
same UI
different presentation
rather than:
destroy UI A
create UI B
This is one reason DOM identity can matter independently of framework state.
4.5. Background preparation of expensive interaction surfaces
Suppose an application can predict the next likely interaction:
A framework may want to prepare the subtree before it becomes visible:
This is related to React's use of hidden Activity for background preparation. React documents that hidden Activities can render their content at lower priority so that code and data can be prepared before the content is shown. (react.dev)
For Solid, the interaction with the new asynchronous reactive model makes this particularly interesting:
Whether this should be considered part of the same primitive is an open design question.
4.6. Temporary ownership by overlays
Consider a UI where an underlying surface is temporarily covered by another interaction:
The underlying canvas may contain substantial local UI state:
The overlay should not require the underlying surface to be reconstructed when it disappears. More importantly, an application may want the underlying surface to become temporarily inactive rather than simply invisible. This exposes the deeper distinction between: not visible and not currently participating in the interaction
4.X The number of examples is unlimited
5. What existing solutions tell us
Several frameworks already solve parts of this problem, but they do so differently. That divergence is useful because it shows that the fundamental problem is broader than any one implementation.
5.1. React
React 19.2 introduced:
with two modes: visible or hidden
React defines hidden Activity as retained UI whose Effects are cleaned up while its state is preserved. Hidden descendants can still render updates at lower priority. When the Activity becomes visible, Effects are recreated. Therefore combines several ideas:
This is strong evidence that a mainstream UI system considers “hidden but retained” to be a meaningful semantic state. However, React's implementation is built around Fiber, lanes, component state, and rendering priority. Solid does not share that architecture. Therefore React gives us prior art for the problem, not necessarily the correct design.
5.2. Vue
Vue's abstraction is:
Vue caches component instances and uses explicit activation/deactivation lifecycle hooks. It also supports bounded caches with max, allowing inactive instances to be evicted. The important conceptual difference is: component instance caching, rather than general reactive activity state This leads to a useful design question for Solid: Is the primitive fundamentally about components, or about retained reactive subtrees? Solid has no need to define the problem in terms of framework-managed component instances.
5.3. Angular RouteReuseStrategy
Angular's RouteReuseStrategy demonstrates a narrower approach. A router can decide: detach, store, reattach, destroy for a route subtree. This is valuable evidence for retention, but it is intentionally router-specific. A Solid primitive should not necessarily force the general concept into a router abstraction.
5.4. Lit
Lit also has a cache directive that preserves template instances instead of recreating them when switching between templates. This reinforces an important distinction: preserve UI identity, can be useful even when the UI is no longer visible. Again, however, DOM/template retention is not the same thing as a reactive lifecycle.
6. The fundamental design question
The previous systems suggest that the problem actually contains several independent questions.
When a subtree becomes invisible:
The critical point is that these are separate dimensions. A good Solid API should not accidentally answer all seven merely because one particular framework already did.
7. A semantic decomposition
Instead of defining Activity immediately as a component behavior, we can decompose the concept.
This immediately exposes why the problem is interesting. A single boolean called hidden may be insufficient to describe the underlying semantics.
8. Candidate semantic models
Before choosing an API, it is useful to consider possible models.
Model A - Visual retention only
state retained
DOM retained
reactivity unchanged
effects unchanged
This is approximately what developers already get from
display: noneIt is useful, but it does not introduce a new runtime lifecycle.Model B - Retention + effect suspension
state retained
DOM retained
effects stopped
reactivity partly active
This is closest to React Activity's public behavior.
Model C - Full reactive suspension
state retained
DOM retained
effects stopped
derived stopped
propagation stopped
The subtree becomes effectively dormant until restored.
Model D - Retention + lazy invalidation
A particularly interesting possibility for Solid is:
state retained
DOM retained
effects suspended
invalidations retained
computation deferred
Conceptually:
Model D - Retention + lazy invalidation
A particularly interesting possibility for Solid is:
state retained
DOM retained
effects suspended
invalidations retained
computation deferred
Conceptually: This is not a proposal to adopt that implementation. It is included because Solid's fine-grained dependency graph may make this model particularly natural. The important question is whether it is both:
semantically correct, technically practical. That should be investigated rather than assumed.9. Why Solid may have a unique opportunity
Solid's runtime already has explicit reactive ownership. A subtree is not merely a visual grouping. It has an associated ownership structure containing computations, effects and cleanup behavior. This is a materially different starting point from a Virtual DOM renderer. Solid 2 also makes asynchronous computation increasingly integrated with its reactive model rather than treating asynchronous data as a completely separate category. The current Solid 2 work therefore makes questions about retained reactive work particularly relevant. That suggests a possible Solid-native interpretation:
rather than:
Whether that interpretation is actually desirable is precisely what the discussion should determine.
10. DOM preservation is a separate question
One tempting implementation is to physically move hidden DOM elsewhere. Modern browsers now expose moveBefore(), which performs a state-preserving move rather than the traditional remove-and-reinsert sequence. The DOM specification explicitly defines it as moving a node while preserving associated state. However, moveBefore() remains limited-availability and is not yet Baseline. It also imposes constraints on connected versus disconnected trees. Therefore this RFC deliberately does not define DOM relocation as part of the semantic contract. A future implementation may use: display:none, moveBefore(), renderer-specific retention depending on the renderer and browser capabilities. The semantic requirement should be: A retained subtree should not be unnecessarily recreated merely because it temporarily becomes invisible. The mechanism should remain an implementation question.
11. The strongest argument for a first-class primitive
A reasonable objection is: "Developers can already keep content mounted and hide it." That is true. But that implementation gives us only: visible vs invisible. It does not give us a framework-level concept of: visible vs retained vs destroyed
The same distinction appears independently in several ecosystems:
React ~> Activity
Vue ~> KeepAlive
Angular ~> RouteReuseStrategy
Lit ~> cache
The API shapes differ because the frameworks differ. That suggests the common denominator is not a particular API. The common denominator is the need to preserve identity across a visibility transition.
12. Why not make this purely a router problem?
Router reuse is only one instance of the problem. A tab can need retention without being a route. A modal can need retention without being a route. A complex component inside an editor can need retention without being either. A router-specific solution therefore captures only: route reuse, while the underlying problem is subtree reuse. Angular demonstrates that route retention has independent value, but its API is intentionally scoped to routing. A lower-level primitive could support routing without making routing part of the core API.
13. Why not automatically cache everything?
Because retention is not free. Keeping more UI alive means: more memory, more retained DOM, more retained state. Different frameworks therefore make different choices. Vue provides an explicit bounded cache through max. React leaves retention policy largely to the application. This RFC does not propose deciding that question yet. A first-class primitive and an automatic cache are different abstractions:
Combining them prematurely would unnecessarily enlarge the API.
14. Why this is not simply “React Activity for Solid”
There is obvious prior art in React, and the proposed name is intentionally borrowed only tentatively. But the architectural questions differ. React answers: How should Fiber treat hidden work? Solid must answer: What should happen to an owned fine-grained reactive subtree, when its UI is temporarily inactive? React's hidden Activity still permits lower-priority updates. A Solid implementation might instead discover that: lazy invalidation is preferable or full continuation might be preferable, or a hybrid based on computation kind might be possible. The RFC should therefore avoid assuming the answer.
15. A proposed conceptual state machine
The simplest useful abstraction is:
where VISIBLE means the subtree is currently presented. RETAINED means the subtree still exists and can be shown again without reconstruction. DESTROYED meansits lifetime has ended. This state machine is intentionally minimal. It does not yet say what the runtime should do with every signal or effect. That is a feature, not a defect.
16. Questions the Solid community needs to answer
Before finalizing any API, the following questions should be discussed.
State
What must survive a visibility transition?
Should createEffect continue running? Should it be paused? Should it be recreated on activation?
Reactivity
If an external signal changes while the subtree is retained:
should the subtree:
Should async work continue? Should it be cancelled? Should its latest value be retained? Should a hidden subtree be allowed to prefetch data?
DOM
Should hidden DOM:
Composition
How should nested retained subtrees behave?
Routing
Can the router later build route caching on top of the primitive?
SSR
Should a retained-but-hidden subtree be rendered on the server?
Hydration
Can retained subtrees become independent hydration units?
These questions should precede API finalization.
17. A possible API — intentionally non-binding
An API could look like:
or:
or:
The choice is deliberately left open. The purpose of this RFC is to establish the semantics before deciding which syntax best expresses them.
18. What would make a Solid implementation different?
A successful implementation should ideally preserve Solid's existing strengths:
Fine-grained updates
The primitive should not require introducing a generic component rerender cycle.
Explicit ownership
Retention should integrate with Solid's ownership and cleanup model rather than inventing a parallel component cache model.
Composability
It should work for:
rather than belonging to a single subsystem.
Minimal runtime cost
An application that does not use the primitive should pay no meaningful cost.
Renderer independence
The conceptual semantics should be meaningful beyond the DOM, even if the initial implementation is DOM-oriented.
19. Possible long-term consequences
If the basic retained-subtree abstraction proves useful, it could become a foundation for several higher-level features.
These are possible future uses, not requirements of the initial API.
20. Non-goals
This RFC does not currently propose:
The proposal is intentionally smaller: Define whether Solid should have a first-class representation of UI that is retained across visibility changes.
21. The central proposal
The actual proposal is therefore deliberately modest: Solid should investigate a first-class abstraction for retaining a UI subtree across visibility changes. The desired transition is:
VISIBLE ~> temporarily not needed ~> RETAINED ~> needed again ~> VISIBLErather than forcing every application to choose between: destroy everything and keep everything running22. Conclusion
The web platform and modern UI frameworks increasingly distinguish not currently visible from no longer needed. React's Activity, Vue's KeepAlive, Angular's route reuse, and Lit's caching mechanisms all address different manifestations of that distinction. Solid currently provides excellent primitives for both ends of the lifecycle: create and react, dispose. What is missing is a clearly defined intermediate semantic state: retain, but temporarily do not present. This RFC does not claim to know the correct implementation yet. It proposes that the problem itself should become an explicit part of Solid's design discussion. The next step should be to determine the semantics of that state before deciding whether the final API should be called
<Activity />or something else. The API is not the proposal. The lifecycle concept is.All reactions