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

Allow for . in attribute names #42

Open
Alxandr opened this issue Sep 29, 2015 · 15 comments
Open

Allow for . in attribute names #42

Alxandr opened this issue Sep 29, 2015 · 15 comments

Comments

@Alxandr
Copy link

Alxandr commented Sep 29, 2015

I would like if . was allowed in attribute names, like this:

<tag-name some.attribute="value" />

which would be transformed into (using react)

React.createElement("tag-name", { "some.attribute": foo });

It's allowed in HTML to have attributes with dots in them.

@RReverser
Copy link
Contributor

What should

<tag-name some={{ a: 1 }} some.b=2 />

and

<tag-name some.a=1 some={{ b: 2 }} />

and

<tag-name some="1" some.b="2" />

do?

It brings too much questions, conflicts and undefined behavior IMO.

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

None of those are problematic. If you read my transformation, it should be like this:

React.createElement("tag-name", { "some": {a: 1}, "some.b": "2"});
React.createElement("tag-name", { "some.a": "1", "some": {b}});
React.createElement("tag-name", { "some": "1", "some.b": "2"});

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

Let me clarify some more. This are not object expressions/merging. It's just treating the entire attribute (dots and all) as a string. So you can't do attrs.some.a, you'll have to do attrs['some.a'].

@sebmck
Copy link

sebmck commented Sep 29, 2015

I don't think @RReverser was talking about the syntactic ambiguity rather that in JavaScript a . is used to represent property access and the use of it as a key is very confusing.

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

@sebmck well, he said "conflicts and undefined behavior". Of which there are none.

@NekR
Copy link

NekR commented Sep 29, 2015

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

@NekR it's not at all that it doesn't work. It's that I have a HTML element that expects an attribute with . in it's name.

@NekR
Copy link

NekR commented Sep 29, 2015

@Alxandr Hmm.. interestingly, why?

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

@NekR No particular reason. It was made that reason a good while ago. It's a custom element, and I've been using it for a while. Now, I could obviously change it, which is probably what I'll end up having to do (as opposed of today, where I customly do element.setAttribute). I just thought JSX should support this, mostly given that I figured it would be easy to implement, and not cause any issues with existing code. And HTML supports it.

@NekR
Copy link

NekR commented Sep 29, 2015

@Alxandr yes, good reason. But there might be a problem with current <foo.Bar> which in supported implementations means foo.Bar() (or create(foo.Bar)) and if <div foo.bar=""> will translate just to {'foo.bar': ''} it may cause some confusions. Anyway, at some point I also thought that JSX should support it was confused that it don't. Interestingly what other people think here.

@Alxandr
Copy link
Author

Alxandr commented Sep 29, 2015

@NekR I'd argue that those are fairly different though. One is an attribute, the other is an element name. Though, I've already stated my opinion. So I'll let the rest discuss.

@treshugart
Copy link

Big +1 to this. I think the question worth asking is: is there benefit in not conforming to the HTML spec? And if so, does it outweigh the benefits that consumers get by having that predictability?

@amiller-gh
Copy link

amiller-gh commented Jun 10, 2017

Hey all, opening this old discussion back up! Just had a major use case come up in a new project that this language feature would be great syntactic sugar for.

Side note: while looking into this language feature, I found an inconsistency between the JSX spec and Babylon's implementation that more work on this issue may help resolve, but should probably be fixed regardless (excuse me for the length of this comment!)

The JSX parser in Babylon currently allows namespaced tag names with member expressions:

<test:foo.bar></test:foo.bar>

However, this is wrong according to the current JSX spec, where JSXNamespacedNames do not allow member expressions, only identifiers:

JSXElementName :
- JSXIdentifier
- JSXNamespacedName
- JSXMemberExpression

JSXAttributeName :
- JSXIdentifier
- JSXNamespacedName

JSXIdentifier :
- IdentifierStart
- JSXIdentifier IdentifierPart
- JSXIdentifier NO WHITESPACE OR COMMENT `-`

JSXNamespacedName :
- JSXIdentifier `:` JSXIdentifier

JSXMemberExpression :
- JSXIdentifier `.` JSXIdentifier
- JSXMemberExpression `.` JSXIdentifier

This grammar allows tag names like these:

<foo:bar></foo:bar>
<foo.bar></foo.bar>

But does not allow for namespaced member expression tags like the Babylon parser currently does:

<test:foo.bar></test:foo.bar>

By updating the definition of JSXNamespacedName to:

JSXNamespacedName :
- JSXIdentifier : JSXIdentifier
- JSXIdentifier : JSXMemberExpression
- JSXMemberExpression : JSXIdentifier
- JSXMemberExpression : JSXMemberExpression

The spec will match what Babylon currently parses as valid JSX, and will have the fringe benefit of enabling namespaced, member expression attributes:

<div attr:biz.baz="value"></div>

One more small update to JSXAttributeName and we get support for un-namespaced attribute names that @Alxandr asked for.

JSXAttributeName :
- JSXIdentifier
- JSXMemberExpression
- JSXNamespacedName

However, none of the above addresses @RReverser and @NekR's concern about behavior ambiguity. One option that addresses both use cases is to mirror the behavior used by tag names, and preserve the use of member expressions as data accessors, where:

let tagNames = { div: 'div' };
let attrsNames = { custom: "some.value" };
<tagNames.div attrsNames.custom="value" />;

may be transformed to

let tagNames = { div: 'div' };
let attrsNames = { custom: "some.value" };
React.createElement(tagNames.div, { [attrsNames.custom]: "value" });

My use case: a library that exports attribute names for use on elements that may change between dev and production builds and should be applied dynamically, but where you want to apply them in a cleaner, more statically analyzable way than with spread attributes:

import lib from "my-library";
return ( <div lib.customProp="value" ></div> );

I think theres value in adding this language feature, and I'm happy to help make updates to assorted parsers / transpilers to support it if the proposal moves forward – the example Babylon implementation I've been playing with is here:
amiller-gh/babylon@de84728

@syranide
Copy link
Contributor

My use case: a library that exports attribute names for use on elements that may change between dev and production builds and should be applied dynamically, but where you want to apply them in a cleaner, more statically analyzable way than with spread attributes:

return ( <div [lib.customProp]="value" ></div> ); is the answer to that (computed property names). Although I have no idea why changing attribute names between dev and prod is a good idea.

@amiller-gh
Copy link

Ah well look at that, I just re-created an existing proposal! Thanks for calling it out @syranide. Should this issue be closed in favor of #21?

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

No branches or pull requests

7 participants