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

No reason to prohibit use of JS keywords in JSX? #2781

Closed
taoeffect opened this issue Dec 29, 2014 · 13 comments
Closed

No reason to prohibit use of JS keywords in JSX? #2781

taoeffect opened this issue Dec 29, 2014 · 13 comments

Comments

@taoeffect
Copy link

So my understanding based on the docs is that class is prohibited as an HTML attribute in JSX, but I see no reason for this.

One example given in the guide of using className instead of class shows that the transformation results in this JS:

var root = React.createElement('ul', { className: 'my-list' }, child);

But this is easily fixed by quoting className as 'class':

var root = React.createElement('ul', { 'class': 'my-list' }, child);

So, unless I'm missing something obvious, can we please have our normal HTML back? ^_^

@antoinegrant
Copy link

👍

@akiran
Copy link

akiran commented Dec 29, 2014

+1
Some times I mistakenly use 'class' in jsx and wonder why css styles are not working.

@zpao
Copy link
Member

zpao commented Dec 29, 2014

class is not prohibited. You can use it. But you're right that we don't support it for DOM components.

We are already deviating from pure HTML (it's XML, we camelCase attributes, have other enforcements). Overall we're using the JS API for attributes so className fits in (node.className = 'whatever').

We're already years deep on this commitment so we're not backing out, sorry.

@zpao zpao closed this as completed Dec 29, 2014
@taoeffect
Copy link
Author

@zpao wrote:

class is not prohibited. You can use it. But you're right that we don't support it for DOM components.

That sounds like a self-contradiction. How can I use it if you don't support it?

We are already deviating from pure HTML (it's XML, we camelCase attributes, have other enforcements).

Why?

Overall we're using the JS API for attributes so className fits in (node.className = 'whatever').

This takes less than one minute to fix:

  • Search: .className =
  • Replace: ['class'] =

@gaearon
Copy link
Collaborator

gaearon commented Dec 29, 2014

That sounds like a self-contradiction. How can I use it if you don't support it?

You can use a prop called “class” on your custom components, if you feel like it.
React DOM components use “className” because this is what DOM property is named.

This takes less than one minute to fix:

What would be the practical benefit of breaking “name attributes after DOM API properties” convention?

@zpao
Copy link
Member

zpao commented Dec 29, 2014

Why?

To make it all easier to understand and parse. An HTML parser is hard and has lots of edge cases. XML-ish is much easier to parse because it has stricter rules. The other part of this is that we are trying to make it clear that this still becomes pure JS with minimal processing.

  • Search: .className =
  • Replace: ['class'] =

node['class'] = doesn't work in any browser AFAIK. It's not part of the DOM API.

@taoeffect
Copy link
Author

To make it all easier to understand and parse. An HTML parser is hard and has lots of edge cases.

Since you're familiar with the internals of React (and I am not) I will just have to take your word on this and assume that there's no third-party parser that can be used to solve this problem.

node['class'] = doesn't work in any browser AFAIK. It's not part of the DOM API.

Ah, I didn't understand that you were using the DOM className attribute (again, an internals thing that you would know and I wouldn't).

That was the misunderstanding, and now @akiran's suggestion makes sense to me, and your response, likewise, also makes sense.

The downturn in #2782 was the result of a gap in perspective ("new user" vs "knees deep in the implementation"), made worse by there seeming to be a lack of desire/effort to close that gap.

The reasons why making JSX similar to HTML is challenging are not obvious from the explanations in the docs, and they weren't clear to me until your comment just now above where you said "node['class'] = doesn't work in any browser AFAIK". That's when it clicked for me.

Just some feedback. Sorry for the harsh words in the other thread, they were the result of misunderstanding.

@gaearon
Copy link
Collaborator

gaearon commented Dec 29, 2014

Ah, I didn't understand that you were using the DOM className attribute (again, an internals thing that you would know and I wouldn't).

React uses DOM property names instead of HTML attribute names in many instances because they match semantics more closely.

For example, take style. In HTML, it's a string like "border-color: red; font-size: large". But this doesn't make sense for JSX because we want React be able to diff individual styles.

Of course we could also say JSX needs a CSS parser as well, but, aside from providing no benefit, this would also complicated developer's life, as generating strings is harder than settings properties on objects.

So we need an object-ish style in JSX that would allow something like { 'border-color': 'red', 'font-size': 'large' } as a value. But we already have this kind of API, and it's called DOM.

In DOM, node.style is an object and not a string, and indeed, its keys are camel cased and not hyphenated. Do we need to “fix DOM” as well? It's find-and-replace too.. (Now that I think of it, DOM API allows setting/reading styles via hyphenated API but I'm not sure it's consistently supported across all browsers. But it's not true for node's attributes—no hyphenated properties there.)

Do you see that JSX will in most cases be much closer to DOM API than to HTML? Because it's generated by JS and not some server template language, it needs to be very JS-friendly, or it would be awkward to use from within JS. That's the reason DOM API doesn't match HTML either. (DOM specification also uses tabIndex instead of HTML's tabindex, same for all other properties.)

So that's where JSX's “use DOM property name” convention is coming from.

@taoeffect
Copy link
Author

Thanks for the detailed explainer @gaearon. I feel like it would be valuable to include something explicit like that in the docs (and maybe it was there, but for whatever reason it didn't click the first time).

So one of the main challenges seems to be the ability to diff the changes, as you say:

we want React be able to diff individual styles.

On the other hand, at least as far as class and other HTML attributes go, it still seems doable.

Thinking it over more, I actually don't understand entirely this response that @zpao gave to @akiran:

We actually did that initially but it takes away from real uses cases where you want class to be the prop. Remember, Composite Components are a vital part of React, not just DOM components. For example . Transforming that to React.createElement(Teacher, {className: "Physics"}) is a terrible idea

This is probably my n00bness speaking, but that seems to be a misunderstanding of the suggestion.

It's not that class would be transformed to className for components, but that class is used to indicate className (somewhere along the line) when dealing with HTML DOM nodes (not React components).

React components don't have or need className as far as I understand, so in that case class would simply be accessed as props.class.

And when not using JSX to create HTML components (as in <a class="red"></a>), you still wouldn't use {className: ... }, but pass in {'class': ... }, and then internally React would map that to the DOM className property.

Note I am no longer advocating this be done (since I get the feeling it may be asking a lot); at this point I am just curious.

@gaearon
Copy link
Collaborator

gaearon commented Dec 30, 2014

I see your latter point now and I agree it's doable although it would be breaking “use DOM property names” convention mentioned by @zpao. It's not all-encompassing, e.g. there is no corresponding classList in JSX (#309, #2440, reactjs/react-future#11), but it's a rule of thumb the team's been using for quite a while.

React tries to stress that “it's all just JS” and there's no templating language so appealing to “the guts” (DOM API) as the reference point makes sense IMO.

See also for some context around that decision:
#346
#328
#269
https://groups.google.com/forum/#!topic/reactjs/xovHWHGHPCA
https://gist.github.com/zpao/6321691

@chenglou
Copy link
Contributor

(Wow we're still on this! lol)

IIRC the thing that killed this is let {class} = obj. Restructuring and pulling out the class key. Doesn't work because it conflicts with the upcoming class keyword. That should end the discussion right?

@elicwhite
Copy link
Member

The online react compiler seems to use class instead of className

@AndreKR
Copy link

AndreKR commented Jun 12, 2015

I got here wondering the same thing as @taoeffect, and from the conversation I think this is a documentation issue.

On http://facebook.github.io/react/docs/jsx-in-depth.html it says (emphasis mine):

Since JSX is JavaScript, identifiers such as class and for are discouraged as XML attribute names.

In my opinion this suggests that valid JSX has to be valid JavaScript and therefore I cannot use "class".

It should be changed to something like "Since JSX expressions are evaluated into DOM nodes, their attributes should follow the same naming conventions, i.e. className instead of class."

Because that's the point, isn't it?

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

8 participants