Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessing children #106

Open
jacobjuul opened this issue May 17, 2023 · 12 comments
Open

Accessing children #106

jacobjuul opened this issue May 17, 2023 · 12 comments
Labels
accepted Accepted for development enhancement New feature or request

Comments

@jacobjuul
Copy link

Let's say I have this webcomponent

<my-component>some text I want access to in react</my-component>

I assumed the text would be available as children in the react component, but it's not as far as I can tell. Can I access this.textContent somehow instead?

@christopherjbaker christopherjbaker added the question Further information is requested label May 18, 2023
@christopherjbaker
Copy link
Contributor

We explored a few options for direct access, but the only option we found entailed crawling the DOM children and turning them into React nodes; while functional, it was very messy and create a lot of React key errors, so it wasn't really a viable solution.

If you just want to render that text, and don't need access to the value, slots are what you want. Given how you've written the above component, you can render that text anywhere you want by rendering <slot></slot> (as many times as you want). If you want "fallback" content to show if they use doesn't provide a value, you can put that inside the slot tag. If you want multiple of these user-defined content blocks, you can use named slots, too.

<my-component>
  <span slot="content1">some text I want access to in react</span>
  <p slot="content2">some other content I want access to in react</p>
</my-component>

Then render these with <slot name="content1"></slot> and <slot name="content2"></slot>.

If you need direct access to the value, I would suggest putting it in an attribute on the WC, or setting it on a property after the component is mounted.

@christopherjbaker christopherjbaker changed the title Accessing this in React Accessing children May 19, 2023
@christopherjbaker
Copy link
Contributor

If you think this would benefit from further discussion, or if not, I'd invite you to join our community discord. There are quite a few threads there about R2WC, and t's become a really great spot to ask questions, share knowledge, and connect about other interests too.

@jacobjuul
Copy link
Author

Thanks so much. I actually ended up solving it with a slot although not exactly what I wanted.

@christopherjbaker
Copy link
Contributor

If you can explain your needs a bit more, I might be able to incorporate something into a future version that solves the problem better.

@rowthan
Copy link

rowthan commented May 31, 2023

I solved as follow:
this code worked in react component.

const slotName = 'children' //  set a slot name id whatever you like.
const {children} = props; // this children is comes from React children property original.
useEffect(function() {
    // pick all children from custom element and set a slot property for them.
    const children: HTMLElement[] = props.container?.host?.children;
    if(children){
      for(let i=0; i<children.length; i++){
        children[i].setAttribute('slot', slotName)
      }
    }
  },[])

  return (
    <div>
       {children}
      // set a slot for html element.
       <slot name={slotName}></slot>
    </div>
  )

how about put this logic into React-to-web-component?
i think it won't cause some issue like React key error?

@rowthan
Copy link

rowthan commented May 31, 2023

what cause this case is confused me.
i did not meet this case while creating custom element by svelte.
so what's the problem? is it a limited by web component or svelte has solved this issue in some way?

@rowthan
Copy link

rowthan commented May 31, 2023

I have got the reason in this code. it's not a limit by custom element but React.

React render need a root element as the root. so you provide this(custom-element) as its root. so after render, the origin children element by html will be replaced.


if (options.shadow) {
    this.container = this.attachShadow({
      mode: options.shadow,
    }) as unknown as HTMLElement
  } else {
    this.container = this
  }

this[contextSymbol] = renderer.mount(
      this.container,
      ReactComponent,
      this[propsSymbol],
    )

To avoid prevent this issue. how about select or create a root instead of this?
like bellow:

let rootContainer = this;
const thisCustomElement = this;

// 1. check if `thisCustomElement ` has a some children
const hasChildren = this.CustomEelement.children.length > 0;
if(hasChildren){
  const childRoot = document.createElement('div');
  thisCustomElement.appendChild(childRoot);
  rootContainer = childRoot;
}

@rowthan
Copy link

rowthan commented May 31, 2023

I have got the reason in this code. it's not a limit by custom element but React.

React render need a root element as the root. so you provide this(custom-element) as its root. so after render, the origin children element by html will be replaced.


if (options.shadow) {
    this.container = this.attachShadow({
      mode: options.shadow,
    }) as unknown as HTMLElement
  } else {
    this.container = this
  }

this[contextSymbol] = renderer.mount(
      this.container,
      ReactComponent,
      this[propsSymbol],
    )

To avoid prevent this issue. how about select or create a root instead of this? like bellow:

let rootContainer = this;
const thisCustomElement = this;

// 1. check if `thisCustomElement ` has a some children
const hasChildren = this.CustomEelement.children.length > 0;
if(hasChildren){
  const childRoot = document.createElement('div');
  thisCustomElement.appendChild(childRoot);
  rootContainer = childRoot;
}

@christopherjbaker check this please.

@rowthan
Copy link

rowthan commented Jun 1, 2023

replace all origin children or create a new child root node maybe could be a property choice when using custom html.
both of then are useful.
one is need keep origin node as children.
another don't need keep it can be used as a fallback on connected error or custom html not work.

@TheRarita
Copy link

I started conversation on this topic a while ago on Discord as well, here is the link for the thread for reference: https://discord.com/channels/1007137664606150746/1113836418716942358/1113836418716942358

@christopherjbaker christopherjbaker added enhancement New feature or request accepted Accepted for development and removed question Further information is requested labels Oct 4, 2023
@duoduoObama
Copy link

I have also encountered this problem. This problem is too critical. If children cannot include nested components, and do this in attributes, the converted components will be quite troublesome to use.

@guenyoo
Copy link

guenyoo commented Feb 15, 2024

That's a usecase we would need as well for web-components. An Accordeon-Component for example doesn't need to know it's children beforehand and it would be necessary to just be able to drop other components/content in.

Is there a workaround that works in the meantime?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted Accepted for development enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants