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

Bypass synthetic event system for Web Component events #7901

Open
staltz opened this Issue Oct 6, 2016 · 54 comments

Comments

Projects
None yet
@staltz

staltz commented Oct 6, 2016

To use a Web Component in React, you must directly attach an event listener to the React ref for that WC. We could change the implementation so that when React detects a custom element (tag names with dashes, like my-component), it will bypass the synthetic event system (and the whitelist) and just attach the event listener on the element itself.

Why bypass the synthetic event system? Because anyway we already need to bypass it manually when using a Web Component. I'm not so familiar with the React codebase, but this naive approach seems to work. Whoever uses Web Components in React can be responsible for whatever downsides that would cause, maybe in performance, I don't know. They are already having those (supposed) downsides, this issue is just about the convenience of WC usage inside React.

I was about to send a PR for this, but thought of opening an issue. I looked through the issues and didn't see any existing one related to the handling of WC events.

What is the current behavior?

A WC custom event (e.g. flipend) must be handled by attaching the event listener directly to the element in componentDidMount using a ref.

http://jsbin.com/yutocopasu/1/edit?js,output

React v15.1.0

class HelloMessage extends React.Component {
  handleHelloClick() {
    this.refs['foo'].toggle();
  }

  handleFlipend(ev) {
    console.log('Handle flip end');
  }

  componentDidMount() {
    this.refs['foo'].addEventListener('flipend', ev =>
      this.handleFlipend(ev);
    );
  }

  render() {
    return (
      <div>
        <div onClick={ev => this.handleHelloClick()}>
          Hello {this.props.name}, click me!
        </div>
        <brick-flipbox class="demo" ref="foo">
          <div>front</div>
          <div>back</div>
        </brick-flipbox>
      </div>
    );
  }
}

What is the expected behavior?

A WC custom event can be handled with onMyEvent={ev => this.handleMyEvent(ev)} on the ReactElement corresponding to the WC.

class HelloMessage extends React.Component {
  handleHelloClick() {
    this.refs['foo'].toggle();
  }

  handleFlipend(ev) {
    console.log('Handle flip end');
  }

  render() {
    return (
      <div>
        <div onClick={ev => this.handleHelloClick()}>
          Hello {this.props.name}, click me!
        </div>
        <brick-flipbox onFlipend={ev => this.handleFlipend(ev)} class="demo" ref="foo">
          <div>front</div>
          <div>back</div>
        </brick-flipbox>
      </div>
    );
  }
}

PS: this snippet above still has the ref, but for unrelated reasons. Ideally we wouldn't need refs for handling events of WCs.

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Oct 11, 2016

https://github.com/webcomponents/react-integration will create a React component from a web component constructor and give you custom event support.

treshugart commented Oct 11, 2016

https://github.com/webcomponents/react-integration will create a React component from a web component constructor and give you custom event support.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 20, 2016

Member

As long as we only support attributes. I don't see a problem doing this for the heuristic if (typeof props[propName] === 'function') element.addEventListener(propName, props[propName], false). The only concern would be if we should have some heuristic for normalizing the event name. I'm not really a fan of converting things like onXxx into xxx after doing that in MooTools. The other concern is related to #6436 and how we'd handle capture/bubble/passive/active etc.

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

Member

sebmarkbage commented Oct 20, 2016

As long as we only support attributes. I don't see a problem doing this for the heuristic if (typeof props[propName] === 'function') element.addEventListener(propName, props[propName], false). The only concern would be if we should have some heuristic for normalizing the event name. I'm not really a fan of converting things like onXxx into xxx after doing that in MooTools. The other concern is related to #6436 and how we'd handle capture/bubble/passive/active etc.

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Oct 20, 2016

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

It feels like that statement is clumping all web components into a single bag of poor design, which in many cases they are, but it doesn't mean you can't optimise for the ones that are designed well. A couple paradigms I'm trying to push in the community (and with SkateJS) are:

  • events up, props down
  • use props as your source of truth, sync attributes to props when you can

Monica Dinculescu mentioned the former and Rob Dodson the latter in their Polymer Summit talks, so I think that's something they're trying to espouse. It's unfortunate the primitives don't make this more obvious, but I think that comes with the nature of most browser built-ins these days.

React not setting props, and not supporting custom events, is the reason we've had to maintain that React integration library I posted above (https://github.com/webcomponents/react-integration). It's worth looking at as a source of some patterns that are definitely working for us in production. It's also worth noting that the patterns employed there are also used in Skate's wrapper around Incremental DOM. We set props for everything we can, falling back to attributes as a last resort.

In the integration lib, events have their own special convention, similar to React's. This in particular is something to pay attention to because adding event listeners if prop is a function - without checking the name for something like /^on[A-Z].*/ - will prefer events over properties.You could flip that around and set props if prop in element and leave it up to the web component to addEventListener() when the onClick property is set. This creates a little more work for the component, but means you don't have to do the prefix checking if you're not a fan.

treshugart commented Oct 20, 2016

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

It feels like that statement is clumping all web components into a single bag of poor design, which in many cases they are, but it doesn't mean you can't optimise for the ones that are designed well. A couple paradigms I'm trying to push in the community (and with SkateJS) are:

  • events up, props down
  • use props as your source of truth, sync attributes to props when you can

Monica Dinculescu mentioned the former and Rob Dodson the latter in their Polymer Summit talks, so I think that's something they're trying to espouse. It's unfortunate the primitives don't make this more obvious, but I think that comes with the nature of most browser built-ins these days.

React not setting props, and not supporting custom events, is the reason we've had to maintain that React integration library I posted above (https://github.com/webcomponents/react-integration). It's worth looking at as a source of some patterns that are definitely working for us in production. It's also worth noting that the patterns employed there are also used in Skate's wrapper around Incremental DOM. We set props for everything we can, falling back to attributes as a last resort.

In the integration lib, events have their own special convention, similar to React's. This in particular is something to pay attention to because adding event listeners if prop is a function - without checking the name for something like /^on[A-Z].*/ - will prefer events over properties.You could flip that around and set props if prop in element and leave it up to the web component to addEventListener() when the onClick property is set. This creates a little more work for the component, but means you don't have to do the prefix checking if you're not a fan.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 20, 2016

Member

@treshugart Most people seem to find this counter-intuitive but my preference would be to effectively just call Object.assign(element, props). It sounds like you'd be a fan of that approach as well? Maybe there is still hope to change the Web Components ecosystem to prefer that - and indeed React promoting that style would perhaps help.

@staltz What do you think about that approach?

Member

sebmarkbage commented Oct 20, 2016

@treshugart Most people seem to find this counter-intuitive but my preference would be to effectively just call Object.assign(element, props). It sounds like you'd be a fan of that approach as well? Maybe there is still hope to change the Web Components ecosystem to prefer that - and indeed React promoting that style would perhaps help.

@staltz What do you think about that approach?

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Oct 20, 2016

@sebmarkbage I like that approach but I think there are a few things to consider (and you're probably already aware):

  1. Props don't work for all elements. SVGElement will error if you set width as a property, for example because it's readonly.
  2. Attributes don't work for all elements. HTMLInputElement needs value set as a property, for example because the attribute does not 2-way sync once the property is set or a user sets a value.
  3. Some web components may have edge-cases where an attribute-only handler is necessary (aria-*, maybe).
  4. Attributes with dashes (my-property) reflected to camel-cased props (myProperty). What is the behaviour here? Probably fine to not worry about this case because the consumer can just use <x-element myProperty={something} />.
  5. Attributes with the same name as the property. What happens if the property is only a getter (no set() or writable: false)? There's no way for the consumer to prefer the attribute. Maybe this is something that is enforced; that the component author must provide a setter or the consumer has to <x-element ref={e => e.setAttribute('some', 'value')} />.
  6. Would this behaviour be applied to custom elements only and how would this be detected if so?

Something like the following might be a little bit more robust:

Object.keys(props).forEach(name => {
  if (name in element) {
    // You might also need to ensure that it's a custom element because of point 1.
    element[name] = props[name];
  } else {
    doWhatReactNormallyDoesWithAttributes();
  }
});

Brainstorming just in case. Overall, I tend to agree with you that it'd be fine for React to just do Object.assign(). It seems like there are ways for the consumer to get around any potential design problems with the component they'd be using.

Maybe there is still hope to change the Web Components ecosystem to prefer that - and indeed React promoting that style would perhaps help.

I sure hope so. I'm trying to and I know the Polymer team is trying to, as well. I think if React did do this, that it'd be a massive help, too.

treshugart commented Oct 20, 2016

@sebmarkbage I like that approach but I think there are a few things to consider (and you're probably already aware):

  1. Props don't work for all elements. SVGElement will error if you set width as a property, for example because it's readonly.
  2. Attributes don't work for all elements. HTMLInputElement needs value set as a property, for example because the attribute does not 2-way sync once the property is set or a user sets a value.
  3. Some web components may have edge-cases where an attribute-only handler is necessary (aria-*, maybe).
  4. Attributes with dashes (my-property) reflected to camel-cased props (myProperty). What is the behaviour here? Probably fine to not worry about this case because the consumer can just use <x-element myProperty={something} />.
  5. Attributes with the same name as the property. What happens if the property is only a getter (no set() or writable: false)? There's no way for the consumer to prefer the attribute. Maybe this is something that is enforced; that the component author must provide a setter or the consumer has to <x-element ref={e => e.setAttribute('some', 'value')} />.
  6. Would this behaviour be applied to custom elements only and how would this be detected if so?

Something like the following might be a little bit more robust:

Object.keys(props).forEach(name => {
  if (name in element) {
    // You might also need to ensure that it's a custom element because of point 1.
    element[name] = props[name];
  } else {
    doWhatReactNormallyDoesWithAttributes();
  }
});

Brainstorming just in case. Overall, I tend to agree with you that it'd be fine for React to just do Object.assign(). It seems like there are ways for the consumer to get around any potential design problems with the component they'd be using.

Maybe there is still hope to change the Web Components ecosystem to prefer that - and indeed React promoting that style would perhaps help.

I sure hope so. I'm trying to and I know the Polymer team is trying to, as well. I think if React did do this, that it'd be a massive help, too.

@justinfagnani

This comment has been minimized.

Show comment
Hide comment
@justinfagnani

justinfagnani Oct 20, 2016

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

I'm not sure what exactly you're referring to, but with Polymer we'd definitely prefer setting properties to setting attributes. Which web components don't handle properties and in what way?

justinfagnani commented Oct 20, 2016

I'd like it better if we could just pass through all props to element properties but it seems like that ship has sailed since most web components aren't designed to handle properties properly. A massive loss to the community IMO.

I'm not sure what exactly you're referring to, but with Polymer we'd definitely prefer setting properties to setting attributes. Which web components don't handle properties and in what way?

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 20, 2016

@sebmarkbage I think we can definitely encourage folks to write components that support the Object.assign approach you mentioned above. As @treshugart mentioned, I spoke about doing this in my Polymer Summit talk based on our previous twitter discussion. Having easy event support in React would also be great.

robdodson commented Oct 20, 2016

@sebmarkbage I think we can definitely encourage folks to write components that support the Object.assign approach you mentioned above. As @treshugart mentioned, I spoke about doing this in my Polymer Summit talk based on our previous twitter discussion. Having easy event support in React would also be great.

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 20, 2016

Talk is here: https://www.youtube.com/shared?ci=256yfQG-abU

I also mentioned the need to dispatch events for state changes so libraries like React can revert those changes (similar to the way React handles the native input checkbook element)

robdodson commented Oct 20, 2016

Talk is here: https://www.youtube.com/shared?ci=256yfQG-abU

I also mentioned the need to dispatch events for state changes so libraries like React can revert those changes (similar to the way React handles the native input checkbook element)

@nhunzaker

This comment has been minimized.

Show comment
Hide comment
@nhunzaker

nhunzaker Oct 20, 2016

Collaborator

events up, props down

Yes. I think there would be benefits outside of web components too. I wonder if we'd see libraries rely less on the context API when they could just emit a custom event.

I don't see a problem doing this for the heuristic if (typeof props[propName] === 'function') element.addEventListener(propName, props[propName], false).

@sebmarkbage Unless you know if any current work here, I'd be happen to stencil something out.

Collaborator

nhunzaker commented Oct 20, 2016

events up, props down

Yes. I think there would be benefits outside of web components too. I wonder if we'd see libraries rely less on the context API when they could just emit a custom event.

I don't see a problem doing this for the heuristic if (typeof props[propName] === 'function') element.addEventListener(propName, props[propName], false).

@sebmarkbage Unless you know if any current work here, I'd be happen to stencil something out.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 20, 2016

Member

@nhunzaker Well I think that what is being discussed here would be an alternate strategy.

We would not support addEventListener('click', fn). We would instead support element.onclick = fn;

Member

sebmarkbage commented Oct 20, 2016

@nhunzaker Well I think that what is being discussed here would be an alternate strategy.

We would not support addEventListener('click', fn). We would instead support element.onclick = fn;

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Oct 20, 2016

Yeah I think I'm ok with the idea of Object.assign(element, props) and element.onflipend = fn. Just to understand why you proposed this, is it just to avoid translating onFoo to foo? Or are there more reasons?

staltz commented Oct 20, 2016

Yeah I think I'm ok with the idea of Object.assign(element, props) and element.onflipend = fn. Just to understand why you proposed this, is it just to avoid translating onFoo to foo? Or are there more reasons?

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 20, 2016

Member

A problem with properties, attributes, events and children is that you have to know which one to use so you end up with heuristics or explicit namespaces. I don't think explicit namespaces is very ergonomic.

Properties are more powerful than attributes because:

  • Properties can have rich data types. E.g. boolean for checked or complex objects like style. Typed CSSOM will let us have specific data types for individual style properties too.
  • In HTML, properties can always control and represent the current visible state of an element. Whenever they diverge, properties is the source of truth - like in the case of HTMLInputElement's value. The only exception is that you can set progress into an indeterminate state - which is just an oversight. As @treshugart pointed out the exception to this is mostly random things added carelessly outside of the normal process - such as RDF or custom elements built by third parties. SVG does have some properties that can't be set in the normal way, but usually you can do that using style instead which are just nested normal properties. These are edge cases that can be dealt with by a library like React DOM that knows about these.
  • Properties have the benefit that they can be reflected over. You can't detect if an attribute or event is accepted or not because they're all accepted so you can't add runtime warnings for wrong attribute names. You can also use that for workarounds, e.g. fallback to something else if a property is not available.

So if we only had one, I'd prefer it to be properties.

That leaves events. If we use a heuristic, that affects performance negatively since we have to create mappings for it at runtime. It also means that we're claiming a whole namespace. It means that custom elements can't provide an onFoo property if they wanted to. For example, with infinite scrolls there's a pattern like onCreateRow that isn't just a simple a event but a callback that's invoked to create a row for a particular index.

I think that would be unfortunate to claim a whole namespace prefix or type when the precedence of element.onclick = fn is a much simpler model.

Of course, that will still leave us "children" as special but that's kind of a unique property of React that children of components can be any type of value so we'll have to concede that one constrained special case.

Member

sebmarkbage commented Oct 20, 2016

A problem with properties, attributes, events and children is that you have to know which one to use so you end up with heuristics or explicit namespaces. I don't think explicit namespaces is very ergonomic.

Properties are more powerful than attributes because:

  • Properties can have rich data types. E.g. boolean for checked or complex objects like style. Typed CSSOM will let us have specific data types for individual style properties too.
  • In HTML, properties can always control and represent the current visible state of an element. Whenever they diverge, properties is the source of truth - like in the case of HTMLInputElement's value. The only exception is that you can set progress into an indeterminate state - which is just an oversight. As @treshugart pointed out the exception to this is mostly random things added carelessly outside of the normal process - such as RDF or custom elements built by third parties. SVG does have some properties that can't be set in the normal way, but usually you can do that using style instead which are just nested normal properties. These are edge cases that can be dealt with by a library like React DOM that knows about these.
  • Properties have the benefit that they can be reflected over. You can't detect if an attribute or event is accepted or not because they're all accepted so you can't add runtime warnings for wrong attribute names. You can also use that for workarounds, e.g. fallback to something else if a property is not available.

So if we only had one, I'd prefer it to be properties.

That leaves events. If we use a heuristic, that affects performance negatively since we have to create mappings for it at runtime. It also means that we're claiming a whole namespace. It means that custom elements can't provide an onFoo property if they wanted to. For example, with infinite scrolls there's a pattern like onCreateRow that isn't just a simple a event but a callback that's invoked to create a row for a particular index.

I think that would be unfortunate to claim a whole namespace prefix or type when the precedence of element.onclick = fn is a much simpler model.

Of course, that will still leave us "children" as special but that's kind of a unique property of React that children of components can be any type of value so we'll have to concede that one constrained special case.

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 22, 2016

I took a stab at implementing the model discussed above. @sebmarkbage can you let me know if this matches your thinking?

class XCheckbox extends HTMLElement {
  connectedCallback() {
    this.addEventListener('click', this._onclick);
  }
  disconnectedCallback() {
    this.removeEventListener('click', this._onclick);
  }
  _onclick(e) {
    this.checked = !this.checked;
    this.dispatchEvent(new CustomEvent('checkchanged', {
      detail: { checked: this.checked }, bubbles: false
    }));
  }
  set oncheckchanged(fn) {
    this.removeEventListener('checkchanged', this._oncheckchanged);
    this._oncheckchanged = fn;
    this.addEventListener('checkchanged', this._oncheckchanged);
  }
  get oncheckchanged() {
    return this._oncheckchanged;
  }
  set checked(value) {
    this._checked = value;
    value ? this.setAttribute('checked', '') : this.removeAttribute('checked');
  }
  get checked() {
    return this._checked;
  }
}
customElements.define('x-checkbox', XCheckbox);

const props = {
  checked: true,
  oncheckchanged: function(e) {
    console.log('oncheckchanged called with', e);
  }
};
const customCheckbox = document.createElement('x-checkbox');
Object.assign(customCheckbox, props);
document.body.appendChild(customCheckbox);

One concern is that element authors have to opt-in to defining a setter to expose a handler for every event that they dispatch. That may end up bloating the elements, especially if they have a variety of events that they expose. Having React do element.addEventListener(propName, props[propName], false) might make element author's lives a bit easier. Just speaking personally, knowing the trade off between an event name heuristic and having to define setters for everything, I'd choose the heuristic.

robdodson commented Oct 22, 2016

I took a stab at implementing the model discussed above. @sebmarkbage can you let me know if this matches your thinking?

class XCheckbox extends HTMLElement {
  connectedCallback() {
    this.addEventListener('click', this._onclick);
  }
  disconnectedCallback() {
    this.removeEventListener('click', this._onclick);
  }
  _onclick(e) {
    this.checked = !this.checked;
    this.dispatchEvent(new CustomEvent('checkchanged', {
      detail: { checked: this.checked }, bubbles: false
    }));
  }
  set oncheckchanged(fn) {
    this.removeEventListener('checkchanged', this._oncheckchanged);
    this._oncheckchanged = fn;
    this.addEventListener('checkchanged', this._oncheckchanged);
  }
  get oncheckchanged() {
    return this._oncheckchanged;
  }
  set checked(value) {
    this._checked = value;
    value ? this.setAttribute('checked', '') : this.removeAttribute('checked');
  }
  get checked() {
    return this._checked;
  }
}
customElements.define('x-checkbox', XCheckbox);

const props = {
  checked: true,
  oncheckchanged: function(e) {
    console.log('oncheckchanged called with', e);
  }
};
const customCheckbox = document.createElement('x-checkbox');
Object.assign(customCheckbox, props);
document.body.appendChild(customCheckbox);

One concern is that element authors have to opt-in to defining a setter to expose a handler for every event that they dispatch. That may end up bloating the elements, especially if they have a variety of events that they expose. Having React do element.addEventListener(propName, props[propName], false) might make element author's lives a bit easier. Just speaking personally, knowing the trade off between an event name heuristic and having to define setters for everything, I'd choose the heuristic.

@justinfagnani

This comment has been minimized.

Show comment
Hide comment
@justinfagnani

justinfagnani Oct 23, 2016

@sebmarkbage I get why properties are preferable to attributes, that's why Polymer defaults to setting properties. Since most Web Components these days are Polymer elements, and Polymer automatically supports properties, I think most Web Components handle properties correctly. Most of the other WC libraries I've seen handle properties correctly as well. If you know of a large set of components that don't support properties, let me know and I'd be glad to we see if I can help fix that massive loss.

@robdodson I don't think it's really feasible to have element authors write their own event handler properties. Events work fine with just addEventListener() and dispatchEvent() and event handler properties are an extra burden and won't be consistently implemented, and aren't even sufficient for many uses of addEventListener(). I'd guess that if addEventListener() were in DOM 0, the event handler properties wouldn't even exist - they're a vestige of an earlier time.

Polymer and Angular (and I believe SkateJS as well) have syntax conventions for declaring a binding to a property, attribute or adding an event handler with HTML attribute names. I don't know JSX, but it seems like since it's not HTML and not JavaScript, there's a lot of leeway to invent its own syntax to unambiguously differentiate between properties attributes and events.

justinfagnani commented Oct 23, 2016

@sebmarkbage I get why properties are preferable to attributes, that's why Polymer defaults to setting properties. Since most Web Components these days are Polymer elements, and Polymer automatically supports properties, I think most Web Components handle properties correctly. Most of the other WC libraries I've seen handle properties correctly as well. If you know of a large set of components that don't support properties, let me know and I'd be glad to we see if I can help fix that massive loss.

@robdodson I don't think it's really feasible to have element authors write their own event handler properties. Events work fine with just addEventListener() and dispatchEvent() and event handler properties are an extra burden and won't be consistently implemented, and aren't even sufficient for many uses of addEventListener(). I'd guess that if addEventListener() were in DOM 0, the event handler properties wouldn't even exist - they're a vestige of an earlier time.

Polymer and Angular (and I believe SkateJS as well) have syntax conventions for declaring a binding to a property, attribute or adding an event handler with HTML attribute names. I don't know JSX, but it seems like since it's not HTML and not JavaScript, there's a lot of leeway to invent its own syntax to unambiguously differentiate between properties attributes and events.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 23, 2016

Member

React intentionally went back on that and claims that single event handlers is a better model and the use cases for multiple event listeners is better solved elsewhere since it leads to confusion about where events flow and which order they flow.

Additionally, the string based event system is difficult to type. Both statically for type systems like TypeScript and Flow, and for optimizing adding lots of event subscriptions at runtime (instead of string based hash maps).

So I don't think it's fair to say that event handler properties are strictly worse.

More over, there are other types of first-class event handlers like Observables that would be nice to support using properties.

The most important feature for interop is reflection. Without reflection you can't make automatic wrappers such as providing a first-class Observables as properties for each available event.

This is something that the event listener system doesn't provide. There is no canHandleEvent(type). Of course, just like attributes, this doesn't really make sense since the stringly typed event system can broadcast any string to any element through bubbling.

Member

sebmarkbage commented Oct 23, 2016

React intentionally went back on that and claims that single event handlers is a better model and the use cases for multiple event listeners is better solved elsewhere since it leads to confusion about where events flow and which order they flow.

Additionally, the string based event system is difficult to type. Both statically for type systems like TypeScript and Flow, and for optimizing adding lots of event subscriptions at runtime (instead of string based hash maps).

So I don't think it's fair to say that event handler properties are strictly worse.

More over, there are other types of first-class event handlers like Observables that would be nice to support using properties.

The most important feature for interop is reflection. Without reflection you can't make automatic wrappers such as providing a first-class Observables as properties for each available event.

This is something that the event listener system doesn't provide. There is no canHandleEvent(type). Of course, just like attributes, this doesn't really make sense since the stringly typed event system can broadcast any string to any element through bubbling.

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 26, 2016

@sebmarkbage those are good points. If you have a moment can you take a look at the sample code I posted and let me know if it seems inline with what you're thinking?

robdodson commented Oct 26, 2016

@sebmarkbage those are good points. If you have a moment can you take a look at the sample code I posted and let me know if it seems inline with what you're thinking?

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 26, 2016

Member

@robdodson Yes, that looks very good to me.

Member

sebmarkbage commented Oct 26, 2016

@robdodson Yes, that looks very good to me.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 26, 2016

Member

If the only problem is boilerplate, I think that is solvable. Initially in user space in terms of libraries that make it easy to create best-practice custom elements. Later a standard helper can be batteries included.

Member

sebmarkbage commented Oct 26, 2016

If the only problem is boilerplate, I think that is solvable. Initially in user space in terms of libraries that make it easy to create best-practice custom elements. Later a standard helper can be batteries included.

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 26, 2016

If the only problem is boilerplate, I think that is solvable. Initially in user space in terms of libraries that make it easy to create best-practice custom elements. Later a standard helper can be batteries included.

Yeah that sounds good to me 👍 @treshugart @staltz what do you guys think?

robdodson commented Oct 26, 2016

If the only problem is boilerplate, I think that is solvable. Initially in user space in terms of libraries that make it easy to create best-practice custom elements. Later a standard helper can be batteries included.

Yeah that sounds good to me 👍 @treshugart @staltz what do you guys think?

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Oct 26, 2016

Looks awesome! I'll reiterate that https://github.com/webcomponents/react-integration currently solves this stuff in userland. That might be a good spot to start collaborating on some of the boilerplate.

treshugart commented Oct 26, 2016

Looks awesome! I'll reiterate that https://github.com/webcomponents/react-integration currently solves this stuff in userland. That might be a good spot to start collaborating on some of the boilerplate.

@pemrouz

This comment has been minimized.

Show comment
Hide comment
@pemrouz

pemrouz Oct 26, 2016

From experience of using vanilla Web Components in a React-like architecture, a few humble suggestions:

  • Don't spray props directly onto the element, do something like Object.assign(element.props, props) instead. This makes it alot easier to debug ($0.props), works better with the immutable paradigm (element.props === props), time travel, avoids clashes, gives the component a chance to interpret the data (especially important if WC extends native element), etc.
  • Don't support attributes. It's much better to have one good consistent way (properties) to deal with data than several partial solutions. At scale, the little benefit gained by trying to make attributes work would be offset by the confusion to many devs. Hopefully this eventually reflects back in WC design.
  • If the component implements some "render" function, invoke it after updating. In my world, essentially this.setState(props) = Object.assign(element.props, props) + .render() (except s/props/state && s/.render()/.draw()) and all components (stateless & stateful) are just function(state){}. This would be great for WCs that implement a declarative render function, rather than having to deal with each change individually.
  • As aforementioned, agree with a standard helper for binding events, or perhaps some JSX syntax addition?

pemrouz commented Oct 26, 2016

From experience of using vanilla Web Components in a React-like architecture, a few humble suggestions:

  • Don't spray props directly onto the element, do something like Object.assign(element.props, props) instead. This makes it alot easier to debug ($0.props), works better with the immutable paradigm (element.props === props), time travel, avoids clashes, gives the component a chance to interpret the data (especially important if WC extends native element), etc.
  • Don't support attributes. It's much better to have one good consistent way (properties) to deal with data than several partial solutions. At scale, the little benefit gained by trying to make attributes work would be offset by the confusion to many devs. Hopefully this eventually reflects back in WC design.
  • If the component implements some "render" function, invoke it after updating. In my world, essentially this.setState(props) = Object.assign(element.props, props) + .render() (except s/props/state && s/.render()/.draw()) and all components (stateless & stateful) are just function(state){}. This would be great for WCs that implement a declarative render function, rather than having to deal with each change individually.
  • As aforementioned, agree with a standard helper for binding events, or perhaps some JSX syntax addition?
@jfrazzano

This comment has been minimized.

Show comment
Hide comment
@jfrazzano

jfrazzano Oct 27, 2016

I hate to chime in on a thread like this but feel I owe it to justin as a deminimus for all his hard work and patience just with me.

As someone building a shard templating engine,designed to approximate functional groups, the unbelievable --excuse my French --expletive it is to json manage data in looped layered attributed that can only pass data strings --makes even the vaguest concept of sacrificing the speed, ease of use and Dom severability available via element properties or in the alternative mapped property proxies an anathema

Via shard templating, or granular web components hundreds of inputs, radically different configs and on the fly changes can be handled with fewer than five fingers worth of event handlers--focus edge cases when attempting to dual focus being the one exception

Attribute based handlers make events specific to the element not the view

Image one of my simplest projects a iuniversal dropdown that takes its items from whatever input or menu calls it.

How do you handle those events via an attribute binding.

I can do it with just the window click / touched listener and some creative refactoring

Focus manipulation from text inputs excepted. Then I do use a "chase" handler that passes the listener to each active text field for the damned tab on Apple

jfrazzano commented Oct 27, 2016

I hate to chime in on a thread like this but feel I owe it to justin as a deminimus for all his hard work and patience just with me.

As someone building a shard templating engine,designed to approximate functional groups, the unbelievable --excuse my French --expletive it is to json manage data in looped layered attributed that can only pass data strings --makes even the vaguest concept of sacrificing the speed, ease of use and Dom severability available via element properties or in the alternative mapped property proxies an anathema

Via shard templating, or granular web components hundreds of inputs, radically different configs and on the fly changes can be handled with fewer than five fingers worth of event handlers--focus edge cases when attempting to dual focus being the one exception

Attribute based handlers make events specific to the element not the view

Image one of my simplest projects a iuniversal dropdown that takes its items from whatever input or menu calls it.

How do you handle those events via an attribute binding.

I can do it with just the window click / touched listener and some creative refactoring

Focus manipulation from text inputs excepted. Then I do use a "chase" handler that passes the listener to each active text field for the damned tab on Apple

@jfrazzano

This comment has been minimized.

Show comment
Hide comment
@jfrazzano

jfrazzano Oct 27, 2016

At a minimum you are gonna burn your wheel and kill your cpu in a complex app

jfrazzano commented Oct 27, 2016

At a minimum you are gonna burn your wheel and kill your cpu in a complex app

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Oct 27, 2016

@robdodson Yeah that's aligned with what I think as well.

Just speaking personally, knowing the trade off between an event name heuristic and having to define setters for everything, I'd choose the heuristic.

I'd also choose the same.

What's the action points with this issue? I'm willing to do something but unsure what, and confused whether @robdodson or @sebmarkbage have intentions to act on this.

staltz commented Oct 27, 2016

@robdodson Yeah that's aligned with what I think as well.

Just speaking personally, knowing the trade off between an event name heuristic and having to define setters for everything, I'd choose the heuristic.

I'd also choose the same.

What's the action points with this issue? I'm willing to do something but unsure what, and confused whether @robdodson or @sebmarkbage have intentions to act on this.

@sebmarkbage

This comment has been minimized.

Show comment
Hide comment
@sebmarkbage

sebmarkbage Oct 27, 2016

Member

To clarify my conclusion: If @robdodson shows that the proposed "best-practice" above is a feasible direction for the Web Components ecosystem including event listeners as properties.

Then React will switch to simply transferring props to the element properties, Object.assign(customElement, reactElement.props) in the next major release.

The next actionable item there would be that someone (maybe Polymer?) provides a way to make it easy to build such Web Components and see if it is viable in the more raw-form Web Components community (as opposed to big libraries).

Member

sebmarkbage commented Oct 27, 2016

To clarify my conclusion: If @robdodson shows that the proposed "best-practice" above is a feasible direction for the Web Components ecosystem including event listeners as properties.

Then React will switch to simply transferring props to the element properties, Object.assign(customElement, reactElement.props) in the next major release.

The next actionable item there would be that someone (maybe Polymer?) provides a way to make it easy to build such Web Components and see if it is viable in the more raw-form Web Components community (as opposed to big libraries).

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Oct 27, 2016

@staltz I've been discussing it with some of the platform engineers on Chrome. They raised some issues around how the native on* properties work with builtins and I think it'd be worthwhile to discuss those. I'm working on a follow up that details the points they covered.

robdodson commented Oct 27, 2016

@staltz I've been discussing it with some of the platform engineers on Chrome. They raised some issues around how the native on* properties work with builtins and I think it'd be worthwhile to discuss those. I'm working on a follow up that details the points they covered.

@robdodson

This comment has been minimized.

Show comment
Hide comment
@robdodson

robdodson Nov 18, 2016

@treshugart

I am curious, though, as to how React will decide how it should set props on an element, as opposed to attributes. This could be troublesome for custom elements needing some things set as attributes, such as aria-.

Good question. It may be the case that some attributes still require a special case. Either using special syntax in React to set the attribute, or React could set it using some kind of heuristic ("any property beginning with aria* gets set as an attribute instead). For what it's worth, there's an effort underway to allow you to set accessibility properties in JavaScript. So in the future, that one piece could be a non-issue 😄

@caridy

My main concern is the shape of the event object, and the potential confusions around it. Today, and based on the example from @robdodson, those events will be custom events with a detail object with an arbitrary shape, which will differ from the existing practices and knowledge base that we will have to fight against (e.g.: the click event always comes with a target reference).

As I understand it, CustomEvent inherits from Event and therefore has the same properties. By calling dispatchEvent we implicitly set the target to the element that's doing the event dispatch. The main unique point is that there's a detail object which can hold extra data.

@treshugart

For 3, setting events (or via symbol) via react, or using a custom syntax wouldn't do this either, right?

I think the idea is that events would be calling addEventListener under the hood. So it would support bubbling at least because the component decides if the event its dispatching bubbles or not.

I actually wouldn't mind having a convention in web components I build to expose properties corresponding to custom events supported by the component as it enables a declarative API without leaving it up to each templating engine to have custom semantics around how it binds events.

If there was a standards based way of doing this I'd be cool with it to. For instance, the observedAttributes array is an easy way for Custom Elements to observe attribute mutations. You could imagine something similar like:

static get exposedEvents() {
  return ['foo-changed', 'bar-input, ...];
}

Somehow exposedEvents would automagically generate on* properties

robdodson commented Nov 18, 2016

@treshugart

I am curious, though, as to how React will decide how it should set props on an element, as opposed to attributes. This could be troublesome for custom elements needing some things set as attributes, such as aria-.

Good question. It may be the case that some attributes still require a special case. Either using special syntax in React to set the attribute, or React could set it using some kind of heuristic ("any property beginning with aria* gets set as an attribute instead). For what it's worth, there's an effort underway to allow you to set accessibility properties in JavaScript. So in the future, that one piece could be a non-issue 😄

@caridy

My main concern is the shape of the event object, and the potential confusions around it. Today, and based on the example from @robdodson, those events will be custom events with a detail object with an arbitrary shape, which will differ from the existing practices and knowledge base that we will have to fight against (e.g.: the click event always comes with a target reference).

As I understand it, CustomEvent inherits from Event and therefore has the same properties. By calling dispatchEvent we implicitly set the target to the element that's doing the event dispatch. The main unique point is that there's a detail object which can hold extra data.

@treshugart

For 3, setting events (or via symbol) via react, or using a custom syntax wouldn't do this either, right?

I think the idea is that events would be calling addEventListener under the hood. So it would support bubbling at least because the component decides if the event its dispatching bubbles or not.

I actually wouldn't mind having a convention in web components I build to expose properties corresponding to custom events supported by the component as it enables a declarative API without leaving it up to each templating engine to have custom semantics around how it binds events.

If there was a standards based way of doing this I'd be cool with it to. For instance, the observedAttributes array is an easy way for Custom Elements to observe attribute mutations. You could imagine something similar like:

static get exposedEvents() {
  return ['foo-changed', 'bar-input, ...];
}

Somehow exposedEvents would automagically generate on* properties

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 10, 2017

Contributor

@sebmarkbage I see that react@16.0.0-alpha was released today - does that have the new support you talked about for custom elements, where everything is properties instead of attributes?

Also, one thing I have noticed with React@15 that could also possibly be improved is support for the className prop (and maybe other react-specific properties for DOM elements). In React@15 the following code does something unexpected (at least to me as a user):

/* Rendering <Foo /> will result in the actual DOM having a `classname` attribute. For example, the real dom will look like this:
 * <button is="x-button" id="2" classname="custom_styles" />
 */
class Foo extends React.Component {
  render() {
    return <button is="x-button" id="2" className="custom_styles" />
  }
}

Once React starts sending those as properties instead of attributes, then it seems like the id and className properties will work just fine, since they are already implemented as properties of HTMLElement. However, are there any edge cases where that behavior won't work as expected? Not sure if there is, but thought you guys might know.

Contributor

joeldenning commented Jan 10, 2017

@sebmarkbage I see that react@16.0.0-alpha was released today - does that have the new support you talked about for custom elements, where everything is properties instead of attributes?

Also, one thing I have noticed with React@15 that could also possibly be improved is support for the className prop (and maybe other react-specific properties for DOM elements). In React@15 the following code does something unexpected (at least to me as a user):

/* Rendering <Foo /> will result in the actual DOM having a `classname` attribute. For example, the real dom will look like this:
 * <button is="x-button" id="2" classname="custom_styles" />
 */
class Foo extends React.Component {
  render() {
    return <button is="x-button" id="2" className="custom_styles" />
  }
}

Once React starts sending those as properties instead of attributes, then it seems like the id and className properties will work just fine, since they are already implemented as properties of HTMLElement. However, are there any edge cases where that behavior won't work as expected? Not sure if there is, but thought you guys might know.

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 11, 2017

Contributor

Answering my own question above: React@16.0.0-alpha does not have support for this yet. I have created #8755 to add it to react@16, though

Contributor

joeldenning commented Jan 11, 2017

Answering my own question above: React@16.0.0-alpha does not have support for this yet. I have created #8755 to add it to react@16, though

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jan 11, 2017

Member

FYI, 16.0.0-alpha is not representative of what will end up in 16.
We only cut the release to test some changes related to React Native.

Member

gaearon commented Jan 11, 2017

FYI, 16.0.0-alpha is not representative of what will end up in 16.
We only cut the release to test some changes related to React Native.

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 11, 2017

Contributor

@gaearon I see. Is there somewhere I can read about 16? Has it been decided when it might be released? Is there a roadmap or tentative list of what might be in it?

Contributor

joeldenning commented Jan 11, 2017

@gaearon I see. Is there somewhere I can read about 16? Has it been decided when it might be released? Is there a roadmap or tentative list of what might be in it?

@rnicholus

This comment has been minimized.

Show comment
Hide comment
@rnicholus

rnicholus Jan 11, 2017

The related issues milestone is filled with cases, but I'm not personally sure if this is fully representative of the final plans for 16.

rnicholus commented Jan 11, 2017

The related issues milestone is filled with cases, but I'm not personally sure if this is fully representative of the final plans for 16.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jan 11, 2017

Member

There's no definitive list because we're working on a complete rewrite of the reconciler ("Fiber"—see the talk, some info, progress, some more info, more detailed progress), and it is not yet clear if we will ship it in 16 or wait until 17. The work on Fiber is currently prioritized before other issues.

You can read our weekly meeting notes to keep track of our progress and planning. I expect that we will talk about beginning to plan for 16 and establishing its scope soon, but we have not yet done that.

Member

gaearon commented Jan 11, 2017

There's no definitive list because we're working on a complete rewrite of the reconciler ("Fiber"—see the talk, some info, progress, some more info, more detailed progress), and it is not yet clear if we will ship it in 16 or wait until 17. The work on Fiber is currently prioritized before other issues.

You can read our weekly meeting notes to keep track of our progress and planning. I expect that we will talk about beginning to plan for 16 and establishing its scope soon, but we have not yet done that.

@justinfagnani

This comment has been minimized.

Show comment
Hide comment
@justinfagnani

justinfagnani Jan 12, 2017

@joeldenning I took a quick look at #8755 and it seemed like it didn't provide any way to set attributes on custom elements. There really needs to be a way to set both, as some thing like aria attribute can't simply be set via properties, and plenty of styling scenarios might require attributes that the element doesn't support as reflected properties.

Also, some attribute/property pairs are very different to set. Attribute data-foo="bar" needs to be set as a nested property e.dataset.foo = 'bar', style becomes style.cssText. This difference would mean that you need data structured differently depending on whether it's being set on a custom element or not.

justinfagnani commented Jan 12, 2017

@joeldenning I took a quick look at #8755 and it seemed like it didn't provide any way to set attributes on custom elements. There really needs to be a way to set both, as some thing like aria attribute can't simply be set via properties, and plenty of styling scenarios might require attributes that the element doesn't support as reflected properties.

Also, some attribute/property pairs are very different to set. Attribute data-foo="bar" needs to be set as a nested property e.dataset.foo = 'bar', style becomes style.cssText. This difference would mean that you need data structured differently depending on whether it's being set on a custom element or not.

@justinfagnani

This comment has been minimized.

Show comment
Hide comment
@justinfagnani

justinfagnani Jan 12, 2017

This is related to #7249 :

I really think the best way here is explicit control over whether a prop is set as an attribute or property or as an event handler via addEventListener. These API surfaces of an element are distinct. Even though they're often correlated, they needn't be and sometimes aren't even on built-in elements.

In #7249 there's a suggestion to set a property if an element has a property of that name, and an attribute otherwise. This is problematic for custom element upgrades. An element may be not-upgraded, have an attribute set that should have been a property, and then be upgraded and not be able to read the correct value from the attribute.

justinfagnani commented Jan 12, 2017

This is related to #7249 :

I really think the best way here is explicit control over whether a prop is set as an attribute or property or as an event handler via addEventListener. These API surfaces of an element are distinct. Even though they're often correlated, they needn't be and sometimes aren't even on built-in elements.

In #7249 there's a suggestion to set a property if an element has a property of that name, and an attribute otherwise. This is problematic for custom element upgrades. An element may be not-upgraded, have an attribute set that should have been a property, and then be upgraded and not be able to read the correct value from the attribute.

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 12, 2017

Contributor

@justinfagnani those are good points. I have a question about the upgrading scenario that you brought up, though: In general, don't elements (both native and custom) look at attributes when they are constructed/connected? And then they look at properties after that? In other words, isn't the general convention for both native and custom elements that properties are the source of truth, and that attributes are just for initial configuration? If a custom element follows that convention (of looking at attributes in connectedCallback and properties after that), doesn't the upgrade problem you talked about disappear?

I've been thinking that the goal is to make it easy for React to interoperate with custom elements that follow a convention like the one I described above. It will of course be possible to interoperate with custom elements that break the convention (via refs), but it will be easy to interoperate with the ones that do.

Do you agree with that? Or do you lean more towards not establishing such a convention?

Contributor

joeldenning commented Jan 12, 2017

@justinfagnani those are good points. I have a question about the upgrading scenario that you brought up, though: In general, don't elements (both native and custom) look at attributes when they are constructed/connected? And then they look at properties after that? In other words, isn't the general convention for both native and custom elements that properties are the source of truth, and that attributes are just for initial configuration? If a custom element follows that convention (of looking at attributes in connectedCallback and properties after that), doesn't the upgrade problem you talked about disappear?

I've been thinking that the goal is to make it easy for React to interoperate with custom elements that follow a convention like the one I described above. It will of course be possible to interoperate with custom elements that break the convention (via refs), but it will be easy to interoperate with the ones that do.

Do you agree with that? Or do you lean more towards not establishing such a convention?

@justinfagnani

This comment has been minimized.

Show comment
Hide comment
@justinfagnani

justinfagnani Jan 12, 2017

Elements can certainly look at attributes when they boot up, but only for values that are string serializable.

justinfagnani commented Jan 12, 2017

Elements can certainly look at attributes when they boot up, but only for values that are string serializable.

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 12, 2017

Contributor

Ah that's a good point. So if an element isn't upgraded yet, you may still need to set properties on it because setting it as an attribute won't work if it's not a string. So

if (propName in obj) {
  obj[propName] = value;
} else {
  obj.setAttribute(propName, value);
}

is probably not the right thing to do. Should React consider doing a customElements.whenDefined() and then execute the above code once we're sure that the custom element is defined and things are upgraded?

Contributor

joeldenning commented Jan 12, 2017

Ah that's a good point. So if an element isn't upgraded yet, you may still need to set properties on it because setting it as an attribute won't work if it's not a string. So

if (propName in obj) {
  obj[propName] = value;
} else {
  obj.setAttribute(propName, value);
}

is probably not the right thing to do. Should React consider doing a customElements.whenDefined() and then execute the above code once we're sure that the custom element is defined and things are upgraded?

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Jan 12, 2017

@joeldenning customElements.whenDefined() accepts a name argument for the custom element you're checking for, so React would not only have to know the name of it, but also that it is indeed a custom element with a corresponding definition that will definitely be loaded.

Giving the user full control over if a property, attribute or event is applied to the element means that there's less checks and heuristics that React needs to maintain. It also means the API consumer gets expected behaviour and complete DOM integration. I say DOM because this is really a DOM integration problem, not just custom elements. Integration with the DOM means custom elements inherently work.

treshugart commented Jan 12, 2017

@joeldenning customElements.whenDefined() accepts a name argument for the custom element you're checking for, so React would not only have to know the name of it, but also that it is indeed a custom element with a corresponding definition that will definitely be loaded.

Giving the user full control over if a property, attribute or event is applied to the element means that there's less checks and heuristics that React needs to maintain. It also means the API consumer gets expected behaviour and complete DOM integration. I say DOM because this is really a DOM integration problem, not just custom elements. Integration with the DOM means custom elements inherently work.

@caridy

This comment has been minimized.

Show comment
Hide comment
@caridy

caridy Jan 16, 2017

update: after a couple of months of research, and some prototyping, it seems to us that React will have to do nothing new to support web-components interoperability in both ways:

  • instantiating a defined/or-to-be-defined web component (where events will be handled via addEventListener, just like a regular HTML Element)
  • encapsulating a react component within a web component (where the react component is responsible for controlling the guts of the web component)

@sebmarkbage we can chat next week at TC39, and eventually share the examples, and the docs if it is sufficient in your opinion.

Slotting remains an open question though!

caridy commented Jan 16, 2017

update: after a couple of months of research, and some prototyping, it seems to us that React will have to do nothing new to support web-components interoperability in both ways:

  • instantiating a defined/or-to-be-defined web component (where events will be handled via addEventListener, just like a regular HTML Element)
  • encapsulating a react component within a web component (where the react component is responsible for controlling the guts of the web component)

@sebmarkbage we can chat next week at TC39, and eventually share the examples, and the docs if it is sufficient in your opinion.

Slotting remains an open question though!

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 16, 2017

it seems to us that React will have to do nothing new to support web-components interoperability in both ways

Well, that's not anything new. As most frameworks, nothing needs to be done to support web components. This issue started out as an improvement suggestion on how to avoid addEventListener in the first place.

staltz commented Jan 16, 2017

it seems to us that React will have to do nothing new to support web-components interoperability in both ways

Well, that's not anything new. As most frameworks, nothing needs to be done to support web components. This issue started out as an improvement suggestion on how to avoid addEventListener in the first place.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jan 16, 2017

As a reminder, could we reconsider onFoo => foo conversion? Before we went deep into props vs attrs, Sebastian said:

The only concern would be if we should have some heuristic for normalizing the event name. I'm not really a fan of converting things like onXxx into xxx after doing that in MooTools.

Would be better to have more solid arguments for or against that.

staltz commented Jan 16, 2017

As a reminder, could we reconsider onFoo => foo conversion? Before we went deep into props vs attrs, Sebastian said:

The only concern would be if we should have some heuristic for normalizing the event name. I'm not really a fan of converting things like onXxx into xxx after doing that in MooTools.

Would be better to have more solid arguments for or against that.

@joeldenning

This comment has been minimized.

Show comment
Hide comment
@joeldenning

joeldenning Jan 17, 2017

Contributor

I agree with @staltz -- we've always been able to interoperate with custom elements inside of React. But it would be really nice if (at least for the majority of custom elements) you could do it without using refs + addEventListener + manual setting of dom element properties, inside of componentWillReceiveProps/componentDidMount

Contributor

joeldenning commented Jan 17, 2017

I agree with @staltz -- we've always been able to interoperate with custom elements inside of React. But it would be really nice if (at least for the majority of custom elements) you could do it without using refs + addEventListener + manual setting of dom element properties, inside of componentWillReceiveProps/componentDidMount

@treshugart

This comment has been minimized.

Show comment
Hide comment
@treshugart

treshugart Feb 28, 2017

Wanted to give an update to a proof of concept that helps to solve this problem. I linked to it in #7249 (comment), but here's the gist for convenience.

treshugart commented Feb 28, 2017

Wanted to give an update to a proof of concept that helps to solve this problem. I linked to it in #7249 (comment), but here's the gist for convenience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment