Dynamic
A tag or component chosen at runtime.
Dynamic renders whatever its component prop
names: a tag such as "h2", or a component class. When the
choice changes, it removes the old one and builds the new one. Every
other prop and the children go to what it renders.
Reach for it when the thing to render is data: a heading level from a setting, a view picked by a tab, a component looked up from a field type. For a fixed set of conditions, Switch and Match or Show read better.
Tags
Pass a tag name in component. Props become attributes and
the children go inside the element. Wrap the choice in a function and
it follows a signal.
Components
A component class works the same way. The example keeps the current view
in a signal and gives Dynamic an accessor that reads it.
Each view is a class with its own state.
Click the counter a few times, switch to About and come back: the count starts again at 0, because the old view was disposed and a new one built. Clicking Counter while it is already shown does nothing.
To store a class in a signal, assign .value = Counter.
signal.set(Counter) would call the class as an updater
function. If you want set, write
set(() => Counter).
What component accepts
| You pass | What happens |
|---|---|
component="h2" | That tag, fixed. |
component=${Counter} | That component class, fixed. A class from another copy of Signy counts too, it is recognized by its render method. |
component=${() => view.value} | Called to get the choice. It runs again when a signal it read changes, and returns a tag, a class, a function component, null or undefined. |
null, undefined | Nothing is rendered. |
| Any other function | Called as an accessor, like the arrow function above. |
| Anything else, such as a node or a number | A warning in development, and nothing is rendered. |
This is the rule Show and For use: a function
means "call me", and the call is tracked. Nothing else tells a fixed
choice from a live one in an html template.
Props and children
Everything except component and children is
passed on. On a tag, a function prop is a binding, like anywhere in an
html template. On a component, a prop that changes must be
a function too, and the component calls it, as described in
props and children.
Here the select swaps the tag, the text field feeds the child, and a
function prop keeps the title current. The children are
made once and moved into each new tag.
Props of a component class are read when it is built. If
component stays the same, a changed static prop does not
rebuild it, so pass a function for anything that changes.
When it swaps
- The effect tracks only
componentand the accessor it calls. What the rendered element or component reads does not rebuild it. - It rebuilds only when the choice is a different value (
Object.is). An accessor that returns the same class again keeps the instance, with its state. - On a swap the old branch is disposed first: its effects stop, its
onCleanupcallbacks andonUnmounthooks run, and its nodes leave the page. Then the new one is built in the same place. - Children come from the parent, so they are not disposed with the branch. They are moved into the new element, which keeps their listeners.
Function components
A function that is not a component class is called as an accessor, so a
function component must be returned from one. A bare
component=${Plain} would be called with no arguments.
function Note(props) {
return html`<em>${props.children}</em>`;
}
html`<${Dynamic} component=${() => Note}>Careful</${Dynamic}>`;
In development, Dynamic warns when the choice is neither a
tag name nor a function, for example when an accessor returns a node.
It then renders nothing. A function component that reads
props and was passed bare throws a
TypeError instead, because it is called without any.
In JSX
The same props, as a component. A prop that the compiler turns into a getter stays live on a tag. On a component class, pass a function for anything that changes.
<Dynamic component={() => view.value} user={user} />
<Dynamic component="h2" title={label.value}>
Heading
</Dynamic>
Limits
componentandchildrenare reserved. A target cannot receive props with those names.- Event props (
onClick) andrefare passed once. They are not bindings. - A swap rebuilds everything inside, including state in the old component. Keep state that must survive in the parent or in a store.
- Transitions on enter and leave are not part of
Dynamic.