S
SolidJS•2y ago
eponymous

How do I pass props to child components which are accessed through props.children?

I'm coming upon this kind of issue a lot. In this particular case, I have a <Tabs> component that can have an arbitrary number of <Tab> and <TabContent> children. There are other ways to do this, but this is the way I have chosen. I need to update props.index on the children from the parent; and also set their visibility either through a props.visible property. 1. Is there a way to pass props from parent to child by getting the child through props.children (or some other way)?
16 Replies
Brendan
Brendan•2y ago
Just about to 💤 but quick suggestion for tabs is for parent component to provide a "controller", via context, that holds the state and a way for each tab to set itself as active, etc.
eponymous
eponymous•2y ago
Thanks @brendan_csel , I will try it this way. However I still want to know if it is possible to set a prop on a child component from the parent by accessing the child through props.children.
Brendan
Brendan•2y ago
Using the children helper is recommend. https://www.solidjs.com/docs/latest/api#children Note, that the children are most likely DOM elements though.
REEEEE
REEEEE•2y ago
It isn't exactly what you're looking for I think but someone was working on something like this in another support thread https://discord.com/channels/722131463138705510/1057796568675262514
Brendan
Brendan•2y ago
I'd definitely recommend a parent-provided (ie Tabs) Context as a way for non-trivial UI components to coordinate their state. It means Tabs, Tab, TabContent can all work together without app code needing to pass any props around. Just to repeat myself another way. Accessing the children will give you the return value from the child components, Not the component functions themselves.
eponymous
eponymous•2y ago
Thanks. I got some useful insight from this, though the conversation is a bit hard to follow. But the suggestion here is that props.children only ever refers to the resolved child components (the actual DOM elements) and therefore cannot be accessed as SolidJS components. This is consistent with my experience, however I was (and still am) hoping that there is just something about the prop.children() api that allows for some manipulation prior to compilation of the resoved component. As I'm writing this I see @brendan_csel 's reply saying that this is not the case. In the Solid Blocks library by @lexlohr which also has a Tabs component, I see that he filters the resolved props.children() by testing if the DOM elements match a certain type - where the <Tab> is an <li> and the <TabContent> (to use my own terminology) is a <div>. I suppose there is no way around this. I suppose I could also add classes or custom attributes instead of trying to manipulate props.
Alex Lohr
Alex Lohr•2y ago
I want to rewrite the tabs component to forgo the filtering. I originally focused on the DX, but this is downright prohibitive for SSR/SSG.
eponymous
eponymous•2y ago
Yes, I can see how this would be prohibitive for SSR. Thanks for pointing that out, I can rule out that method now. It seems that using Context is the cleanest way to do this, so I'll do it this way. Would be nice if, in the future, Solid would allow us to interact with children before they are rendered.
Alex Lohr
Alex Lohr•2y ago
My current plan is to move to context for the tabs and use a structure like <Tabs><TabBar><Tab /></TabBar><TabContainer /></Tabs> If you limit children to () => JSX. Element, that already works. But I don't see solid turning its rendering on its head just for this one use case.
eponymous
eponymous•2y ago
I'll have to learn more about this.
Alex Lohr
Alex Lohr•2y ago
A JSX.Element can be null, a string, dependent on where you render a HTMLElement or an object with { t: string[] } or a function returning any of the aforementioned. If the latter is the case, the component is first evaluated when it gets rendered by the parent. That's why we have the children() helper, which does that evaluation for us.
eponymous
eponymous•2y ago
Ah! That does give me some additional perspective. I'm not coming from a strong React/JSX background so I still have much to appreciate about JSX.
Alex Lohr
Alex Lohr•2y ago
JSX only extends the valid expressions to include some XML/HTML style resemblances of DOM elements. It's entirely up to the library to decide what to do with these expressions. React decided to go the createComponent(tagNameOrComponent, props, child1, child2, ...) route. Solid uses Ryan's DOM expressions to turn JSX into reactive code.
deluksic
deluksic•2y ago
I would just like to note that this use case is probably not a pattern you would want to use anyways. This is because there’s no way to know if a child component knows what to do with that prop, let alone do the right thing. Using context really is the better approach where you can be explicit about this interaction. Having said that, maybe you want to access the dom node refs rendered by children and set style for example. This is indeed doable.
eponymous
eponymous•2y ago
@deluksic You're correct in that there's no way to know if a child component could use the prop. And it would necessitate the kind of filtering in the parent which was mentioned earlier in the thread as a bad idea. I'm building it out with Context. I'm considering trying it where child component is a function that pulls in the necessary props upon evaluation, just as an experiment.
Alex Lohr
Alex Lohr•2y ago
I just finished rewriting the tabs component, if it is of any interest to you: https://github.com/atk/solid-blocks/blob/main/src/blocks/tabs.tsx
GitHub
solid-blocks/tabs.tsx at main · atk/solid-blocks
UI building blocks for SolidJS. Contribute to atk/solid-blocks development by creating an account on GitHub.