Skip to content

Add custom element with method #2466

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

mrginglymus
Copy link
Contributor

React 19 has a very naïve heuristic for setting props vs attributes; if it detects a property on the custom element with the same name as the attribute, it sets it as a property. This doesn't work if you have a method on the custom element with the same name as an attribute you are trying to set.

I've attempted to provide a reproduction here; unfortunately this repository does not behave well on Windows or WSL, which are currently my only two options. I will investigate adding support for Windows devs in another PR.

Copy link

google-cla bot commented Dec 8, 2024

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Comment on lines 202 to 214
it('will not overwrite methods', function () {
let root;
render(
<ComponentWithMethods
ref={(current) => {
root = current;
}}
/>
)
let wc = root.wc;
expect(wc.innerText).to.eql('Success');
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably mirror this to Preact too, but Preact will fail for a similar reason:

https://github.com/preactjs/preact/blob/5c9625a56b8d99e905b3beba9c09b5062fe41287/src/diff/props.js#L121-L124

This is more of a limitation in the standard JSX syntax than anything else, framework has to make a guess when it comes to attrs vs props.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to see this across all the libraries and frameworks so they can make an active decision towards better support or not on their own terms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to extend it to as many of them as I can manage; I've manged to get tests mostly running with git bash on windows but it's still not fully happy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might also reframe the test to catch other potential gotchas - readonly fields, etc.

Copy link
Contributor

@trusktr trusktr Dec 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great start, thanks @mrginglymus!

@Westbrook Indeed, it would be great to get this implemented for all the frameworks.

Can we make a new branch for this, and then make this PR merge to that branch instead of main, that way we can get individual PRs merged piece by piece into the branch until all the tests for each framework, and then finally we can make a final PR to merge the branch into main once it is ready? Who has control of the repo to make that branch?

This is more of a limitation in the standard JSX syntax than anything else, framework has to make a guess when it comes to attrs vs props.

@rschristian Solid.js and Pota both solve this within the limitation of JSX syntax, by looking for attr:foo=, prop:foo=, bool:foo=, and on:foo=. React and Preact could do something like that too, without having to update the JSX spec, as foo:bar= is already valid JSX.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Here's an idea.

Perhaps, we don't have to get all tests for all frameworks implemented. We could consider any framework that's missing the test as not passing. Then this would encourage framework authors to chip in (or whoever to contribute it when they can).

Copy link

@rschristian rschristian Dec 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React and Preact could do something like that too, without having to update the JSX spec, as foo:bar= is already valid JSX.

Barely.

foo: is a namespace, not supported by default in Babel (or any other tooling as far as I am aware) and not supported at all in many others. I wrote a PR to support it in Preact months ago but support is pretty limited for utilizing that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, tsc and vite seem to pass through namespaced attrs just fine. However, I don't think we need to solve React's problem here, just ensure that it's been recorded.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh neat, good to know! I believe esbuild didn't support that in the past, unless I'm misremembering.

Copy link
Contributor

@trusktr trusktr Apr 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babel supports JSX namespaced attributes with the throwIfNamespace: false option, but that's not JSX's fault if some framework (f.e. React) doesn't do anything with those attributes.

It gets tiring when the solutions are obvious but frameworks ignore them. That's why I don't ever choose libraries like React with these limitations that are so easy to fix. Better alternatives exist (check out Solid.js for something similar to but fundamentally better than React).

@mrginglymus
Copy link
Contributor Author

I'm a little confused to as to how I'm supposed to add a successfully failing test...

@mrginglymus
Copy link
Contributor Author

This PR now includes tests for all currently supported frameworks. There are many that have now dropped from 100%, mostly I think those using JSX-like syntax. I've tried to check each one's documentation for hints as to how to set attrs rather than props.

Copy link
Contributor

@justinfagnani justinfagnani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good to me so far. Just a couple of comments...

@@ -0,0 +1,40 @@
/**
* @license
* Copyright 2017 Google Inc. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be Copyright 2024

* limitations under the License.
*/

class CEWithoutProperties extends HTMLElement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name this CEWithMethods? Or add a comment on what this class is testing?

@@ -67,7 +67,7 @@ function compareResultsAgainstGoldens(library) {
}
// A constant, to make sure that if we add/remove any tests, that we add that test to all
// tested libraries.
const numberOfTests = 32;
const numberOfTests = 34;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this is adding two tests? It looks like there's just "will not overwrite unwriteable properties"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are only 16 tests on master, 17 on this PR - something must be double-counting them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it's chrome + firefox counted separately

Copy link
Contributor

@justinfagnani justinfagnani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any open issues for this new case?

There's at least facebook/react#31689 for React, but it's closed.

@mrginglymus
Copy link
Contributor Author

mrginglymus commented Aug 6, 2025

Are there any open issues for this new case?

There's at least facebook/react#31689 for React, but it's closed.

I've re-opened it. Is there somewhere in this repo we reference open issues for failing tests?

@mrginglymus
Copy link
Contributor Author

If there's a chance that #2474 might get merged soon, I'd rather that get merged before this - deconflicting this on top of that one will more pleasant than vice versa.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants