is and className attributes not working together on a react element - reactjs

If you go to the React home page and add the attribute className='button' to the first example "A Simple Component" you should get this result:
(i.e. the div with "Hello Jane" now looks like a button)
If you also add the attribute is='super-nice-button' you should get this result:
(i.e. the button styling is gone)
Why you ask? Seems when you combine className with is react doesn't generate a class attribute on the resulting dom node instead it generates a classname (which obviously has no meaning for the browser). Watch the difference below.
With only the class attribute:
With both the class and the is attributes:
My question: Why does react generate classname and not class when using the is attribute on a react element (and essentially destroying all styling)?
(background: I'm using inline-styling (or Fela) and I like to use the is attribute to tag my divs/panels so I can easily see the flow of components when clicking "Inspect Element" without having to tab over to the "React devtools". I understand it's kind of a hack but is is a supported attribute in React and HTML and it's a nice short word :) )

This is likely related to this:
https://github.com/facebook/react/issues/4933
You'll need to set class instead of className if you're pretending it's a WebComponent.
Personally I'd go a different route, still have it processed like a React component, and do it in a different way, or just use the React devtools.
FWIW, this answer was researched on-the-fly. For future reference, here's the flow:
1) Verified behavior using a basic React JSX fiddle. Confirmed.
2) Searched for the is HTML attribute, which led here within first few links:
What is HTML "is" attribute?
3) Looking in the W3C docs I learned the name of what is is used for. Then I searched for "react components w3c custom elements" which led quickly to:
https://github.com/facebook/react/issues/4933
4) Verified using class instead of className on WebComponent-like DOM, same fiddle.
So from complete ignorance and some surprise I'd say I found the answer in about five minutes.

Related

React TypeScript: How to type set Props

Currently I have to do the following:
interface MyCompProps {
someAttr: number
}
I want to use aria-, and then I have to list upfront all aria-* I need. Furthermore, I can't set a simple className on the component. How can I avoid this, i.e. allow normal HTML attributes on component? Or is it a bad practice? I'm skimming the Advanced Guides on reactjs website and nowhere mention that this is a bad practice, so I think it is acceptable.
Note that all aria-* HTML attributes are fully supported in JSX. Whereas most DOM properties and attributes in React are camelCased, these attributes should be hyphen-cased (also known as kebab-case, lisp-case, etc) as they are in plain HTML
Docs

Using custom html element in react

I am using Typescript and REACT and I want to utilize and wrap some custom html elements in my TSX. For example, I am using a library with a customer html element called ch5-button an it is used in a vanilla html file as such
<ch5-button class="shadow-pulse-button" type="default" shape="circle" label="" iconClass="fas fa-award">
</ch5-button>
I did a ton of searching, but seems like i am not even smart enough to get the search correct to find how to do this. I am not even sure if I have the correct import statement to get those elements -- the closest I got was :
declare var CrComLib: typeof import('#crestron/ch5-crcomlib');
...
const ch5Button = new CrComLib.Ch5Button();
console.log("ch5Button");
console.log(ch5Button);
The console.log display <ch5-button></ch5-button> soI have no idea if I am even on the right track to using this thing. The ch5Button is a class with a lot of methods that look pretty much like what an html element would have but I just dont know what to do with it and how to learn a method for using it. I found some sites that explain how to use observables and such but I am sketchy on if I am heading down the right path. I have attached am image of what some if the properties and methods of the ch5Button looks like in chrome debugger.
Can anyone point me in the right direction? I would create a REACT component that wraps this class and can use props to set the correct attributes etc.
I am very comfortable building REACT apps but admittedly, I am not an advanced developer with it yet but doing my best to learn.

class vs className in React 16

I saw that React 16 allows for attributes to be passed through to the DOM. So, that means 'class' can be used instead of className, right?
I'm just wondering if there are advantages to still using className over class, besides being backwards compatible with previous versions of React.
class is a keyword in javascript and JSX is an extension of javascript. That's the principal reason why React uses className instead of class.
Nothing has changed in that regard.
To expand this a bit more. A keyword means that a token has a special meaning in a language syntax. For example in:
class MyClass extends React.Class {
Token class denotes that the next token is an identifier and what follows is a class declaration. See Javascript Keywords + Reserved Words.
The fact that a token is a keyword means that we cannot use it in some expressions, e.g.
// invalid in older versions on Javascript, valid in modern javascript
const props = {
class: 'css class'
}
// valid in all versions of Javascript
const props = {
'class': 'css class'
};
// invalid!
var class = 'css';
// valid
var clazz = 'css';
// valid
props.class = 'css';
// valid
props['class'] = 'css';
One of the problems is that nobody can know whether some other problem won't arise in the future. Every programming language is still evolving and class can be actually used in some new conflicting syntax.
No such problems exist with className.
Update (August 2020):
A comment by Dan Abramov on the same thread:
This was the most controversial part of the proposal. Since then, we
released Hooks, which encourage writing function components. In
function components, we generally suggest using destructuring for
props, but you can't write { class, ... } because it would be a syntax
error. So overall it's not clear that this is ergonomic enough to
actually follow through with. I think it's plausible we'll revisit
this in the future, or at least make class not warn and let people do
what they want. But for now, we'll shelving this idea.
so, nope
(August 2018)
The React team is actually going to switch to class instead of className in the upcoming future (source):
className → class (#4331, see also #13525 (comment) below). This has
been proposed countless times. We're already allowing passing class
down to the DOM node in React 16. The confusion this is creating is
not worth the syntax limitations it's trying to protect against.
Why switch and not support both?
If we support both without warnings, then the community will split
over which one to use. Each component on npm that accepts a class prop
will have to remember to forward both. If even one component in the
middle doesn't play along and implements only one prop, the class gets
lost — or you risk ending up with class and className at the bottom
"disagreeing" with each other, with no way for React to resolve that
conflict. So we think that would be worse than status quo, and want to
avoid this.
So you should stay tuned.
I would still recommend using className as long as this is what the API expects.
Just to shed a little more light, on top of the other good answers already given:
You'll notice that React uses className instead of the
traditional DOM class. From the docs, "Since JSX is JavaScript,
identifiers such as class and for are discouraged as XML attribute
names. Instead, React DOM components expect DOM property names like
className and htmlFor, respectively."
http://buildwithreact.com/tutorial/jsx
Also, to quote zpao (a React contributor / facebook employee)
Our DOM components use (mostly) the JS API so we opted to use the JS
properties (node.className, not node.class).
as of june 2019, the process of changing className to class has been halted, it could be continued later
here is the post by facebook dev explain why
https://github.com/facebook/react/issues/13525
React docs recommend on using cannonical React attribute names rather than the conventional Javascript naming, so even when React allows attributes to be passed through to DOM, it will give you a warning.
From the docs:
Known attributes with a different canonical React name:
<div tabindex="-1" />
<div class="hi" />
React 15: Warns and ignores them.
React 16: Warns but converts values to strings and passes them through.
Note: always use the canonical React naming for all supported attributes.
Class versus className in reactJS
Class is a reserved word or keyword in reactJS as much as function is in the javascript. That is why we use the word "className" to refer to the class.
There is no real explanation by React team on this but one would presume it to be differentiated from reserved keyword "class" in Javascript since its introduction in ES2015+.
Even if you use "class" in element configuration while creating element, it won't throw any compilation/rendering error.
In ReactJS, we are dealing with JSX and not HTML as you all know. The JSX wants you to use className because it is an underlying javascript DOM API! class being a reserved keyword in JS is not the primary reason why we are not using class and instead, using className. It is because we are referring to that DOM API
Firstly, let's think why className was used over class in the first place:
I recently watched a CSS in React conference video by Joel Denning who disagrees that className was used because class is a keyword in JavaScript. I am leaning towards agreeing with him, although I'm still not fully clear. What follows is the explanation from his video and some of my input:
Open up babel and compile the following JSX snippet:
const element = <div className="foo" />;
const element2 = <div class="foo" />;
Babel compiles this to:
var element = /*#__PURE__*/React.createElement("div", {
className: "foo"
});
var element2 = /*#__PURE__*/React.createElement("div", {
"class": "foo"
});
See how class is treated as a string "class", so no issues with JavaScript keywords.
HTML elements have attributes like class, and then once parsed a DOM node is created with properties like className. Difference between attributes and properties? Take a look at What is the difference between properties and attributes in HTML?.
HTML attribute values can only be strings, whereas DOM properties can have any value. When it comes to dealing with class names I'm not sure how this is useful, but it's certainly cleaner to update DOM properties than attributes:
const div = document.createElement('div');
// Attribute update
div.setAttribute('class', 'foo');
// Property update
div.className = 'foo';
Also, updating a DOM property triggers a re-render which ties in nicely with the idea that the name of a class is a mutable state.
Attributes tend to be used to initialise DOM properties, however, the class attribute and className property are reflected i.e. updating the className property causes the class attribute to be updated with the same value... This makes the reasoning as to why className was chosen confusing, maybe it's because semantically properties are associated with values that can update? I have no idea...
It's so confusing that React are allowing class usage alongisde className (as mentioned in the question). From https://github.com/facebook/react/issues/13525:
className → class (#4331, see also #13525 (comment) below). This has been proposed countless times. We're already allowing passing class down to the DOM node in React 16. The confusion this is creating is not worth the syntax limitations it's trying to protect against. We wouldn't do this change by itself, but combined with everything else above it makes sense. Note we can’t just allow both without warnings because this makes it very difficult for a component ecosystem to handle. Each component would need to learn to handle both correctly, and there is a risk of them conflicting. Since many components process className (for example by appending to it), it’s too error-prone.
In my opinion, there is no concrete answer to this question. I like the semantics behind using a property over an attribute to update something, but if you took me back in time to when the decision was made to use className over class I would have said it is unnecessary.
tldr; To answer your question, I would stick with className which avoids the warnings of class, and is the approach that most other React developers are familiar with so your code will be easier to read.
Still not satisfied? Take a read of https://github.com/facebook/react/issues/13525#issuecomment-417818906.
The problem is that the react code you see is not HTML - it is in fact JSX is an extension to javascript (basically javascript + plus a little bit more).
Q:Can we use class to represent the HTML attribute: 'class'?
Given that it is javascript, you cannot use the word class because that is a special javascript word that is "reserved" (javascript prescribes certain words that you can and cannot use).
Given that class is a reserved word, how are you going to write classes in our "html" code jsx, because that word is a 'reserved' word and is not allowed to be used like that? The way around it is to use: "className" instead of "class", so then jsx will know that you are dealing with the html class attribute and not the javascript class keyword.
class can't be used instead of className in React 16, as well as in the former versions.
The reason for this is a bit obscured, probably it's some kind of convention or so.
If this explanation isn't good enough for you, check out my article on hashnode. It's a long and in-depth write-up, therefore your curiosity will probably be satisfied.
you have to use className instead of class in your div code section area

Reactjs overide markdown types with react-markdown

I am using contentful to get markdown to a react component that uses react-markdown to parse the markdown
import ReactMarkdown from 'react-markdown';
<Markdown source={text} />
Would I like to do is to override the Renderer so instead of it rendering ## as an h2 render i can pass a custom component to override the default h2 type to my own h2 component. How can i do that and is there and examples?
One of the options to <ReactMarkdown> is renderers.
One of the common renderers handles headings. If you look at the default rendering you'll see this:
heading: function Heading(props) {
return createElement('h' + props.level, getCoreProps(props), props.children);
},
So pass in your own heading handler. Check the level inside, roughly:
function CustomHeading(props) {
if (props.level !== 2) {
return createElement(`h${props.level}`, getCoreProps(props), props.children);
}
return <MyCustomElement {...props} />
}
If you don't have access to the code that commonmark-react-renderer gives you in the context of your function (which you probably won't) then you'd also need to duplicate what createElement gives you (but it's simple).
Unrelated: I've never used <ReactMarkdown> (but will), but this took me about five minutes of research. I'm including my path to encourage others to dig into their own questions and hopefully give some insight into how such things can be researched.
The react-markdown home page
Scanned through the "Options" section to see if custom rendering was trivially supported
Found the renderers option, which sounded promising
Clicked the link provided in that option's docs
Saw that heading was one of those (which made sense; I'd expect a renderer for every major formatting that Markdown supports)
Opened up the src directory to see if the implementation was easy to find
There was only one file, so I opened it
Searched the page for "heading" and found it
Cut and pasted that code here
The ability to read docs and follow trails is really important.

Input field and React where Input field is not editable because of react id in attr

I have a specific need to only make one input field in a form (legacy code) a react component. So, I wrap the input with a div and render into it the 'new' input field that needs some special behavior.
The problem arises because the input field is no longer editable. I try to type into it.. nothing. I narrowed it down to the following:
<input type="text" **data-reactid=".2.0.0.0.1.0.0.1.2.0"**
When I remove that "data-reactid....", by editing via console, it works.
So when I am using react to sub out one form input field with a react one, it doesn't work unless I manually remove that data-reactid..
Is there a workaround for this, or a reason why this is happening?
Well its just a data attribute written by react to help them render into the DOM more efficiently so it should have no real impact on a input element or any element (unless there is code or style explicitly disabling the input) - I realize that this is no real help - because it happens to you, but this is not typical of react apps with inputs or element with data-attributes.
But if its the only bit of react on the page then that id is a bit long and I would have expected something like ".0" or ".0.0" if its wrapped in a div that react controls.
The react-id is only used by the React engine to work out what elements of the DOM need to be re-written when there are changes to state or props in your components.
One thing I noticed is, typically there would be an ID or in react a ref that you applied to the input in order to interact with it (such as getting its value).
I include the mark-up from a simple entry box on the user login form of a working app, as you can see it's not significantly different from what you have and works on all browsers Windows and Mac down to IE8 included.. (but not any IE below 8) and you need various shims for getting it work on IE8.
<input class="username-text-field" id="user-id" type="text" data-reactid=".0.0.0.1.3.0.0.2">
If none of these apply or you have them covered then practicably here should be no reason why your input should be disabled. It should just act like any other input. Have tried just dropping you component onto a simple HTML page with only the input on it, just to debug through the component in isolation?
That said,
It does feel that loading the entire React engine and wiring up a component to allow a single input field is a little over-kill. I realize that you're trying not to have to recreate exactly the same functionality you already have in react again on the legacy form, but if your render function is not too onerous then maybe a simple bit of JavaScript or JQuery might be the answer as a one off in the legacy solution (rather than the hit for the library) - just a thought

Resources