S
SolidJS4mo ago
Erfan

Rendering dynamic components

Hi Solid community, I could really use your help: Here’s the situation:
function Button(props) {
return (() => {
var _el$ = _tmpl$();
addEventListener(_el$, "click", props.onclick);
insert(_el$, () => props.value, null);
insert(_el$, () => props.children, null);
createRenderEffect(() => className(_el$, button(props.variant)));
return _el$;
})();
}
delegateEvents(["click"]);
export {
Button as default
};
function Button(props) {
return (() => {
var _el$ = _tmpl$();
addEventListener(_el$, "click", props.onclick);
insert(_el$, () => props.value, null);
insert(_el$, () => props.children, null);
createRenderEffect(() => className(_el$, button(props.variant)));
return _el$;
})();
}
delegateEvents(["click"]);
export {
Button as default
};
I’d like to dynamically create these buttons (just an example 😅 ) and nest them into each other at runtime as needed. So I thought I’d store a list of these components in a signal and simply render the children in code like this:
const children = signal([]);
const templates: SolidTemplate[] = [];

function renderChildren(template: SolidTemplate) {
templates.push(template);
children[1](templates);
}

function init() {
const [getChildren] = children;
const c = solidjs.createComponent(() => getChildren());
solidjs.render(() => c, document.getElementById("app"));
}
const children = signal([]);
const templates: SolidTemplate[] = [];

function renderChildren(template: SolidTemplate) {
templates.push(template);
children[1](templates);
}

function init() {
const [getChildren] = children;
const c = solidjs.createComponent(() => getChildren());
solidjs.render(() => c, document.getElementById("app"));
}
Unfortunately, it doesn’t work — nothing gets rendered, and I’m not sure why. Thanks 🙏
37 Replies
zulu
zulu4mo ago
https://playground.solidjs.com/ you can try putting a minimal attempt here and share
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Erfan
ErfanOP4mo ago
thanks i will try
Erfan
ErfanOP4mo ago
i created a minimal attempt. i hope it is understandable https://playground.solidjs.com/anonymous/72464c9b-b0c8-4bf1-9580-b36e966af631
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
zulu
zulu4mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Erfan
ErfanOP4mo ago
thanks alot zulu 🙏
Erfan
ErfanOP4mo ago
can you please take a look why this is not working ? i have tryed to make it like your example but it do`snt work for some reason: https://playground.solidjs.com/anonymous/0cb0b783-99cc-441f-b4d6-6f90d925cd3f
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
ellers
ellers4mo ago
To confirm, a button should render inside another button? My 2c is not to put components into signals or stores, but use any old data and then a For loop or other construct to make buttons out of the data.
ellers
ellers4mo ago
Example: https://playground.solidjs.com/anonymous/d94797d9-c84d-4c04-86a3-6ceaab33d2cf
import { render, createComponent } from "solid-js/web";
import {
createSignal,
Show,
type ParentComponent,
} from "solid-js";

type ClickFunc = () => void

const Button: ParentComponent<{count: number}> = (props) => {
const oneLess = () => props.count - 1
const click = () => {
console.log(new Date().toISOString(), 'click on', props.count)
}

return (
<button
onClick={click}
style={{'z-index': 50-props.count}}
>
{"Button " + props.count}
<Show when={oneLess() > 0}>
<Button count={oneLess()} />
</Show>
</button>
);
}

function Counter() {
const [count,setCount] = createSignal(1);
return (
<>
<h2> Counter: {count()} </h2>
<p><Button count={count()}/></p>
<button onClick={()=>setCount(count=>count-1)}> Decrement </button>
&nbsp;
<button onClick={()=>setCount(count=>count+1)}> Increment </button>
</>
);
}

render(() => <Counter />, document.getElementById("app")!);
import { render, createComponent } from "solid-js/web";
import {
createSignal,
Show,
type ParentComponent,
} from "solid-js";

type ClickFunc = () => void

const Button: ParentComponent<{count: number}> = (props) => {
const oneLess = () => props.count - 1
const click = () => {
console.log(new Date().toISOString(), 'click on', props.count)
}

return (
<button
onClick={click}
style={{'z-index': 50-props.count}}
>
{"Button " + props.count}
<Show when={oneLess() > 0}>
<Button count={oneLess()} />
</Show>
</button>
);
}

function Counter() {
const [count,setCount] = createSignal(1);
return (
<>
<h2> Counter: {count()} </h2>
<p><Button count={count()}/></p>
<button onClick={()=>setCount(count=>count-1)}> Decrement </button>
&nbsp;
<button onClick={()=>setCount(count=>count+1)}> Increment </button>
</>
);
}

render(() => <Counter />, document.getElementById("app")!);
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
No description
zulu
zulu4mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
zulu
zulu4mo ago
this is interesting solution, but in the original code, it might be more about "inversion" of control you can see that he can technically create different elements and manipulate them "externally" he can use different components at each level, etc I am not sure about the objectives
Erfan
ErfanOP4mo ago
Hey thanks alot, i am realy doing exactly the same thing, but for some reason it is not working 😦 i am also coding live, maybe someone can help me out while coding 😅 https://www.twitch.tv/djurab
Twitch
djurab - Twitch
play and chill (muted) join discord to talk or play with me. https://discord.gg/r9GAdP5h
Erfan
ErfanOP4mo ago
thanks you ellers, but like zulu said, i would like to decouple the templating
zulu
zulu4mo ago
In my previous message, in case you missed I have sent a fix
Erfan
ErfanOP4mo ago
yes i saw it, and it works like what i am looking for. But in my env it is not working 😅 i am trying to doing exactly the same thing
zulu
zulu4mo ago
I see, the trick there was to keep the signal "lazy" until you need it that is why I removed the () from the parent this is so the child can preserve the "reactivity"
Erfan
ErfanOP4mo ago
yes and it is working fine. I have also removed now the () and it still will not render for some reason. Thank you for your support 👍 🙂
zulu
zulu4mo ago
Yeah, if you can break it in the playground we can see what is wrong it.
Erfan
ErfanOP4mo ago
thanks, this is exactly what i am trying to do, for some reason it is not working in my env 😕 now i have almost the same codebase but in the playground it is working like expected 😅
Erfan
ErfanOP4mo ago
i have exactly this code running locally and it is not working, it must rely somehow on the dynamic inport. I have checked the results of the imported stuff and every thing is working just solid render is not rendering it to he screen. https://playground.solidjs.com/anonymous/e23957fe-4325-46bf-9e77-d500f3216d51
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
zulu
zulu4mo ago
what do you define as not working in the last playground
Erfan
ErfanOP4mo ago
it is working in the playground, but not working local in my env 😕
zulu
zulu4mo ago
oh I see
zulu
zulu4mo ago
you can try to repro in a more similar environment to local using https://solid.new ( stackblitz )
StackBlitz
Solidjs - Templates - StackBlitz
Vite + solid templates
zulu
zulu4mo ago
is it the exact same code in the local? are you using all recent versions of dependencies ?
bigmistqke
bigmistqke4mo ago
besides the logic that's a bit unusual solid code. couple of remarks/suggestions: - any specific reason why you are working with the compiled output of this Button and App-component? - be careful withButtonComponent.Button({ ... }) as it can cause your component to be re-mount when you read the signal inside the component body (component body = the space of a component that is not jsx/effects/memos): see this playground. You could use createComponent, but it's more idiomatic to use jsx. there is also html-tag template literal and h-function for if you want to use solid without build step. - instead of import("./Button").then(...) you can use solid's lazy-function. then you can remove a lot of the await-code to as solid handles the promise for you. - AppComponent.Solid = Solid; here you bail out of all treeshaking and will bundle all of solid. any specific reason why you want to add Solid as a property to the AppComponent-class? I just noticed I misread, you are importing Solid from ./solid-js (which exports render and createComponent) and not solid-js. still not too sure about the why. - there is nothing wrong with using classes and signals per se, but it's a bit more idiomatic in solid to use functions and return objects instead . that being said classy-solid is a nice package for combining signals with classes. - in your code you are having an async method that you call in the constructor, but you are not awaiting it (async constructors don't exist sadly), this could cause a race condition. i ping pong often between classes/functions and this is the main reason why i am mostly sticking with functions: you can always await createX() but you can't await new X()
Erfan
ErfanOP4mo ago
thanks alot for all the advices, apply all the stuff step by step 🙂 , i have created an minimal env where this is not working like expected. it is on my Github and should like the other playground example just from fileserver but it is not working. https://github.com/ErfanNaz/solid-lazy-example
GitHub
GitHub - ErfanNaz/solid-lazy-example
Contribute to ErfanNaz/solid-lazy-example development by creating an account on GitHub.
Erfan
ErfanOP4mo ago
playground.ts is just to see the code of a little bit clearerplayground.js
zulu
zulu4mo ago
replace your local imports of solid with the esm.sh https://esm.sh/solid-js/web https://esm.sh/solid-js etc and you should see something like this
No description
Erfan
ErfanOP4mo ago
thanks alot Zulu, now i know why it is not working, somehow the signals you are using need to be the same from the web package, otherwise it will not render, i created an example in solidjs playground. In the importmap i chose a nother version of solid-js with an other version, I don't know if this is a design choice ? https://playground.solidjs.com/anonymous/14774db8-f3bb-44e2-9cb3-7d1e2d8d195b
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Erfan
ErfanOP4mo ago
- i am using compiled output, because this is what i will get from somewhere else. - I thought ButtonComponent.Button({}) will just create an reactive template a little bit like lit-html, and i can append end depend it in the dom where i like - there are two different applications one of them will know solid, and the other one don't know solid-js. You can see it in my newest example, signals from solid-js are seperated to signals from solid-js-web - maybe this will explaine why, Because one Application is build with solid-js-web and the other one ist build with signals from solid-js - thanks for the link to classy-solid, looks like a good project - can you create somehow an example where this can fail? i have tryed alot but coudn't make it fail, i can create you an minimal env where we can try out 🙂
zulu
zulu4mo ago
you got it, you need consistent imports and of same versions, because some things need to be shared consistently between modules https://playground.solidjs.com/anonymous/c90669f7-38b6-4f8f-9bfb-5bc44b3cc978
bigmistqke
bigmistqke4mo ago
- gotcha, it's like from a library you import or something? - jsx is almost a regular function call, but it's more like untrack(() => ButtonComponent.Button({...}) as i show in this playground - what is solid-js-web? is it bundled solid-js/web? signals from solid-js are seperated to signals from solid-js-web if they are bundled separately these will not work together as zulu mentioned. (maybe one day if/when signals land in the browser that would be possible, who knows!) - classy-solid is awesome! it's powering lume, a threejs renderer made by truskr. pretty cool stuff 🙂 it's rly cool with solid that you can hack your own abstractions on top of it, it's one of the reasons why i love solid so much. but it also can get easy to get lost in the sauce. when starting of with solid i think it might be easier to stick with more conventional patterns (in this case: using functional components or hooks to compose your templates instead of classes) - this is an example where it would fail: i did delay(5_000).then(() => import("./Button").then(...)) and it broke the demo. if i await the inits it works as expected (just have to wait 5 sec) cooked up a demo together of how it could look like without the classes and the async code in favor of hooks and lazy(...) what is the eventual goal of this exercise? i suppose at the end you want to do more then nest buttons, right?
Erfan
ErfanOP4mo ago
- exactly, I have one application (App 1) bundled with solid-js signals, but it doesn’t know anything about JSX elements. The other application (App 2) uses solid-js/web and JSX.Element, and I’d like it to use the signals from App 1 for the reactive parts. - Yes, using TSX is a great way to create reactive DOM elements — that’s why I want to use it in App 2. - I’m considering using classy-solid, but I’ll try a few other approaches first. - I’ve created a minimal environment to demonstrate what I’m trying to do using the async approach. https://playground.solidjs.com/anonymous/1391db1d-072e-4ccc-84b7-a99aed2bb0b5
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Erfan
ErfanOP4mo ago
exactly the parent child relation is not controlled by App2, it will be controlled by App 1
bigmistqke
bigmistqke4mo ago
- but it doesn’t know anything about JSX elements - you don't have access to a build step for this App 2? because once the jsx is compiled, solid also does not have a notion of jsx. it's not like in react where you end up with a vdom. once compiled it's just html-elements and signals/effects. - other application (App 2) uses solid-js/web and JSX.Element, and I’d like it to use the signals from App 1 for the reactive parts. - as mentioned before, this will not work if you create 2 separate bundles because solid relies on some module-globals. in fact, the app that uses solid-js/web will most likely also contain solid's signals/effects, so you end up with solid bundled 2 times. you could create a separate chunk that both apps load in, or load solid in from a cdn (or even better: not have 2 apps!) - I’ve created a minimal environment to demonstrate what I’m trying to do using the async approach. - mm, i am not really the wiser from this example, it seems to me like a cleaned up version of the demo but without the button-rendering and it contains the same issues I mentioned with that demo: you are calling async code but you are not awaiting it, which could cause issues if you have later code that assumes these promises are resolved (like i show with the broken demo) - exactly the parent child relation is not controlled by App2, it will be controlled by App 1 - I meant more: what kind of app are you trying to build. we have been focussing on technical details in our answers, but I think if we would know what the end result is we could mb propose better alternatives. I also would like to know why you are building 2 apps instead of 1. if it's a size issue you can always lazy-load stuff.
Erfan
ErfanOP2mo ago
Sorry for the late response. I initially focused on App1, which is a TypeScript engine with zero dependencies. The engine supports loading components, and I’m able to register Solid along with all the necessary hooks so it can create and render components. Now I just need to dynamically attach it to the right slot. I’ve created a new minimal example where I’m currently stuck. I don’t have much experience with React’s JSX API, so I really appreciate how Solid treats components as simple functions. That aligns perfectly with how the engine works—it stores components as JSX functions with known parameter types.
Erfan
ErfanOP2mo ago
i have created a new mvp where i am struggling right now. Maybe someone can help ? https://playground.solidjs.com/anonymous/a28ef95d-a10e-4976-9ba0-5d910a10454e
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template

Did you find this page helpful?