Why you have to use className in React, but not in Preact?
Tags: react, javascript, webdev, tutorial
Published: 2022-01-13 16:14:09

## State of things
We all know this simple rule. Use `className` instead of `class` if you write JSX.
```jsx
const ExampleReactComponent = () => {
	return <div className="foo">Example React component</div>
}
```
[React docs warns](https://reactjs.org/docs/introducing-jsx.html#specifying-attributes-with-jsx) us about this convention straightaway. And it goes even further, you need to specify all HTML attributes in `camelCase`.

Okay, if it's the way things work, we can get used to it. Since JSX is different from HTML in a lot of ways, it's somewhat justifiable.

Wait a moment. We actually **can** use `class` in JSX, but only if we would use Preact instead of React. 
```jsx
const ExamplePreactComponent = () => {
	return <div class="foo">Example Preact Component</div>
}
```
And it's a legitimate [documented](https://preactjs.com/guide/v10/differences-to-react#raw-html-attributeproperty-names) feature, not a coincidence or a bug. So, the question is - why? 
Why do we **have to** `camelCase` all HTML attributes in React, but not in Preact?

*Disclaimer: If you aren't familiar with JSX, but want to read and understand this article anyway, check out [my other article](https://dev.to/fromaline/hyperscript-the-hidden-language-of-react-3d1f), where we take a look at what JSX is and how it works under the hood.*

## The reason behind the rule

First thing first, let's clearly define the reason behind this rule in React.
The official React docs have a quite vague explanation.

> Since JSX is closer to JavaScript than to HTML, React DOM uses `camelCase` property naming convention instead of HTML attribute names.

It's hard to say solely from this explanation what the real reason is.
So, let's google it and try to find more info!

### It's a reserved keyword

There is [an article](https://www.geeksforgeeks.org/why-react-uses-classname-over-class-attribute/#:~:text=Explanation%3A%20The%20only%20reason%20behind,className%20instead%20of%20class%20attribute.) about this problem on GeeksForGeeks. Let's consider an explanation from it.

> The only reason behind the fact that it uses className over class is that the _**class**_ is a reserved keyword in JavaScript and since we use JSX in React which itself is the extension of JavaScript, we have to use className instead of the class attribute.

First of all, yeah, technically speaking `class` is a reserved keyword in JavaScript for making, so-called, [class declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class) like this one.
```js
class Polygon {
  constructor(height, width) {
    this.area = height * width;
  }
}
```
But we actually **can** use `class` keyword in JavaScript without much trouble.
```js
const obj = {
	class: 'value'
};

const otherObj = {};

otherObj.class = 'value';
```
You may think, it didn't work last time I checked! And you'll be right.
This works only in modern versions of JavaScript. So that's the point? Not exactly.
In older versions of JavaScript, you may easily achieve the same thing by explicitly turning the `class` property into a string literal like so.
```js
const obj = {
	'class': 'value'
};

const otherObj = {};

otherObj['class'] = 'value';
```
Okay, maybe the real reason is separate from this whole reserved-keyword issue. Maybe, it's the JSX itself!

### It's a JSX-specific issue

Just think about it. JSX is an **extension** of JavaScript, not one-to-one clone or so. That's why even though it's tightly coupled with JS, it may propose some other restrictions.

Let's battle-test this theory. We'll declare a simple component with a `className` attribute.
```jsx
const example = <div className="foo">Hello world!</div>
```
Then, we'll put it through Babel transpiler. 
```js
const example = /*#__PURE__*/React.createElement("div", {
  className: "foo"
}, "Hello world!");
```
*[Live example](https://babeljs.io/repl#?browsers=defaults&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=MYewdgzgLgBApgDwIYFsAOAbOMC8MA8AJgJYBuMwGSEEAcqnDgEQBmIITAfABJwYYgYAdxAAnDIQCE-APQlSnIA&debug=false&forceAllTransforms=true&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=true&timeTravel=false&sourceType=module&lineWrap=true&presets=react&prettier=false&targets=&version=7.16.9&externalPlugins=&assumptions=%7B%7D) in Babel REPL, in case you want to check yourself.*

The result is pretty much expected and fully valid. Now let's try another one. Let's use `class` instead of `className` in this try.
```jsx
const example = <div class="foo">Hello world!</div>
```
And after transpilation we get this.
```js
const example = /*#__PURE__*/React.createElement("div", {
  class: "foo"
}, "Hello world!");
```
*[Live example](https://babeljs.io/repl#?browsers=defaults&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=MYewdgzgLgBApgDwIYFsAOAbOMC8MA8AJgJYBuMwGSEEOARAGYgh0B8AEnBhiDAO4gAThkIBCfAHoSpVkA&debug=false&forceAllTransforms=true&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=true&timeTravel=false&sourceType=module&lineWrap=true&presets=react&prettier=false&targets=&version=7.16.9&externalPlugins=&assumptions=%7B%7D) of this try in Babel REPL.*

First of all, it's fully valid, as well as, the former one.
Secondly, Babel transpiles this snippet, like it was nothing new or weird for him. So, it seems like JSX isn't an issue either.

Okay, maybe we'll face some issues in the render phase. Because JSX in itself is just syntax and it doesn't create UI on its own. We need to render JSX somewhere to see the end UI. So we'll try to do exactly that to see, if some problems may arise.

### It's a render function problem
Let's create a simple render function from scratch because obviously React won't allow us to use its render mechanism with `class` instead of `className`.
Our render function will render the result of `React.createElement` to the DOM. But what does the result of `React.createElement` look like?
`React.createElement` returns, so-called, **virtual node**. 
It looks like this in our case.
```js
const example = {
	$$typeof: Symbol(react.element),
    key: null,
    ref: null,
    props: {
	    class: "foo"
    },
    type: "div",
    children: ["Hello world!"],
    _owner: null
}
```
But what is a virtual node anyway?
Virtual node or vnode, in short, is just a lightweight representation of a given UI structure. In the case of the browser, the virtual node represents the real DOM node. React uses virtual nodes to construct and maintain, so-called, virtual DOM, which itself is a representation of real DOM.

*Sidenote: If you want to dig into this whole virtual madness, let me know in the comments and I'll make an article, where we'll go through the whole concept of virtual DOM and make our own implementation of it.*

To implement the render function and check how things work, we only need three basic properties of the vnode.
```js
const example = {
	// defines the type of a given vnode
	type: "div",
	// defines all passed React props and HTML attributes of a given vnode
	props: {
	    class: "foo"
    },
	// contains children of a given vnode
    children: ["Hello world!"],
}
```
*Sidenote: If you want to understand what other properties are and why they are here, let me know in the comments section and I'll make detailed articles with a deep explanation of each individual property.*

Now with new knowledge we are fully ready to create our own render function for vnode tree. 
Let's start with the basics and create element of the passed type.
```js
const render = (vnode) => {
	const el = document.createElement(vnode.type);
	return el;
}
```
Then let's handle the props.
```js
const render = (vnode) => {
	const el = document.createElement(vnode.type);

	const props = vnode.props || {};  
	Object.keys(props).forEach(key => {
		el.setAttribute(key, props[key]);
	});

	return el;
}
```
Next, let's recursively add our children and handle edge-case, in which a child is a string.
```js
const render = (vnode) => {
	if (typeof vnode === 'string') return document.createTextNode(vnode);
	
	const el = document.createElement(vnode.type);

	const props = vnode.props || {};  
	Object.keys(props).forEach(key => {
		el.setAttribute(key, props[key]);
	});

	(vnode.children || []).forEach(child => {
		el.appendChild(render(child));
	});

	return el;
}
```
The last missing piece is actual mounting. So let's do it now.
```js
const renderedExample = render(example);

document.querySelector('#app').appendChild(renderedExample);
```
Now we're good to go. It's time to test how the render function will handle our virtual node with the `class` prop.

It works like a charm!

![screenshot.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642006796053/tNzjaI4g5.png)

*[Live example](https://codesandbox.io/s/jsx-render-function-example-nq55s?file=/src/index.js) on CodeSandbox.*

It renders the `div` with correct class `foo`.
```html
<div class="foo">Hello world!</div>
```
I added this simple bit of CSS to test if our class is in place. And it is, you can verify it yourself!
```css
.foo {
	color: coral;
}
```
Now we are completely sure, that the reason behind `className` usage is not connected somehow to render function. We are sure because we implemented the render function, that uses `class` ourselves. 
Now what? Maybe we should agree that it's some kind of convention and leave things as they are? No, we should take an even closer look at the problem.

## A different approach to the problem
You see, there is a JS framework, called [Preact](https://preactjs.com/). It's an alternative to React with the same API. 
And there is a very interesting statement on its official page.

![preact official page.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642016822259/y8aSULZup.png)

*Closer to the DOM*. Hmm, it's the exact thing, we are looking for. We try to use `class`, which is a native way of adding CSS classes in DOM. And Preact uses this approach, it becomes clear from its [official docs](https://preactjs.com/guide/v10/differences-to-react/#raw-html-attributeproperty-names).
> Preact aims to closely match the DOM specification supported by all major browsers. When applying `props` to an element, Preact _detects_ whether each prop should be set as a property or HTML attribute. This makes it possible to set complex properties on Custom Elements, but it also means you can use attribute names like `class` in JSX:

```jsx
// This:
<div class="foo" />

// ...is the same as:
<div className="foo" />
```

So, let's dig into Preact source code to figure out why it works.

### Explore source code

*Here is a [link](https://github.com/preactjs/preact/blob/master/src/create-element.js#L14) to the source file on GitHub, in case you want to follow along.*

Let's take a look at Preact `createElement` function, which serves similar purpose as `React.createElement`. Here's a snippet from the function body.
```js
function createElement(type, props, children) {
	let normalizedProps = {},
			key,
			ref,
			i;
	for (i in props) {
		if (i == 'key') key = props[i];
		else if (i == 'ref') ref = props[i];
		else normalizedProps[i] = props[i];
	}
    // ...
```
Preact `createElement` function filters out only two properties, `key` and `ref`, and passes others to `normalizedProps`.

*Sidenote: If you're asking yourself, why Preact filters out `key` and `ref` and how these special props are handled internally by Preact, let me know in the comments section. I'll make detailed articles about these two props.*

Then Preact passes the resulting `normalizeProps` to another function, called `createVNode`, and returns the result.
```js
    // ...
	return createVNode(type, normalizedProps, key, ref, null);
}
```
Let's dig into `createVNode` function.

*[Source file on GitHub](https://github.com/preactjs/preact/blob/master/src/create-element.js#L55)*

```js
function createVNode(type, props, key, ref, original) {
	const vnode = {
		type,
		// No props transformation here
		props,
		// ...
	};
	// ...
	// No props transformation here either
	// ...
	return vnode;
}
```
It becomes obvious from the snippet, that the `createVNode` function doesn't do any transformations with passed `props`. It just returns the `props` in the new `vnode` object. And `vnode` object is just a representation of a given DOM element and it'll be rendered to the real DOM in the future, as we now know.

So the question is, how does Preact know either it is a complex property or HTML attribute if it passes all properties directly to the `vnode`, that gets rendered in the end? For example, how does the event system work in this setup? 
Maybe the answer lies in the render phase? Let's give this guess a shot.

There is a function, called `setProperty`, which is responsible for setting a property value on a DOM node, as you may have gathered. This function is the main mechanism of setting properties to DOM nodes in Preact.

*[Source file on GitHub](https://github.com/preactjs/preact/blob/master/src/diff/props.js#L56)*

```js
function setProperty(dom, name, value, oldValue, isSvg) {
	// ...
	else if (name[0] === 'o' && name[1] === 'n') {
		// ...
		dom.addEventListener(name, handler)
	}
}
```

So Preact actually checks whether the property name corresponds to some event and adds an event listener if it's the case. 
Such distinction allows Preact to deal with events passed through `onClick`, `onInput`, and other props like these, but at the same time allows to use standard HTML properties, like  `class` instead of unique-to-JSX `className`.
But how does Preact handle user-defined custom props? The answer lies in the question itself.

You see, we as a developers, may only pass custom properties to our own components. For example, let's define custom `UserDefinedComponent`.
```jsx
// UserDefinedComponent.js
import { h } from 'preact';

const UserDefinedComponent = ({exampleFunc, brandText}) => {
	exampleFunc();

	return (
		<div>
			<p>{brandText}</p>
		</div>
	);
}

export default UserDefinedComponent;
```

And render it in the `App` component.
```jsx
// App.js
import { h } from 'preact';
import UserDefinedComponent from './UserDefinedComponent';

const App = () => {
	return (
		<UserDefinedComponent 
			exampleFunc={() => {
				console.log('Hello world!')
			}
			brandText="Hello world!"
		/>
	)
}
```
As you may see, there is no way how `exampleFunc` and `brandText` would be passed to the real HTML elements. And even if you intentionally do this, the browser will just ignore unknown properties, Preact doesn't need to additionally validate them on its side.

**But why does React use `camelCase` property naming convention instead of HTML attribute names, anyway?**


## The last question
There is no clear answer to this question. We may only make a few guesses.

Maybe, it's really just a convention, that was proposed when React wasn't event public.

Or maybe, React developers want to match [the JavaScript API](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) more closely, than HTML one. Because in JS the standard way to access `Element` class property is `Element.className`.
```js
const element = document.querySelector('.example');

const classList = element.className;
element.className = 'new-example';
```
It doesn't really matter at this point why they've done so. What matters is, that we now understand all nitty-gritty details about it!

## Wrap up

### Today we learned
Let's sum up what we learned today.
- The reason why React uses the `camelCase` property is probably not one of these:
	- `class` is a reserved keyword in JavaScript
	- `camelCase` properties can't be handled by JSX
	- `camelCase` properties mess up render function
- Preact uses standard HTML properties, because:
	- It aims to closely match the DOM specification
	- It detects whether each prop should be set as a property or HTML attribute
- Digging into source code is more fun, than frightening 😄


###  I'm looking forward to similar articles, what should I do?
First of all, if you *really* like this post leave a comment or/and a reaction to let me know, that I am going in the right direction. Any constructive feedback, either positive or negative, will be welcomed 🙏

If you want more content like this right now:
- You may check out my [Deep dive into React codebase weekly series](https://dev.to/fromaline/series/16231), where we take a thorough look at React source code.
- As I already mentioned, I have [an article about obscured history behind JSX](https://dev.to/fromaline/hyperscript-the-hidden-language-of-react-3d1f).

If you want more content like this next week:
- Follow me on [dev.to](https://dev.to/fromaline), I am going to post an episode of the *Deep-dive-into-React-codebase series* this Sunday (January 16) at 6:00 am UTC+0.
- Follow me on [hashnode](https://blog.fromaline.com/), I'll try to do my best to post an article every week or even make a special hashnode-exclusive series.
- Follow me on [Twitter](https://twitter.com/fromaline), if you want to know about every article I made and also read their sum-ups in threads.