1

JavaScript frameworks like React and Svelte don't allow developers to use the class property on a DOM element because the class keyword is reserved in JavaScript. Meanwhile, other frameworks like Vue somehow get around this.

What is it about how Vue is implemented that makes it possible for Vue developers to use the class keyword on elements? I'd imagine it's something with how Vue converts .vue files to HTML, CSS, and JavaScript but I'm curious about specifics.

Edit: Svelte does not use virtual DOM and you can use the class prop with Svelte.

Brady Dowling
  • 4,920
  • 3
  • 32
  • 62
  • Possible duplicate of https://stackoverflow.com/questions/46989454/class-vs-classname-in-react-16/46991278 . – Estus Flask Mar 11 '20 at 13:42
  • Nothing has changed since that moment. Each framework speaks for itself in this regard. It's more comfortable to not use reserved names for props in React because of how ubiquitous destructuring is in components. – Estus Flask Mar 11 '20 at 13:44
  • This is not a duplicate of that. That doesn't mention Vue at all, which is the essence of this question: What does Vue do differently that allows developers to use the `class` property rather than forcing them to substitute with `className`? I've updated the question and title to reflect this. – Brady Dowling Mar 11 '20 at 13:55
  • JSX and render function is a place where the use of `class` reserved word for props can happen in Vue and React but Vue is primarily template-based. JSX is unpopular in Vue but essential in React, that's the difference. In React className is used for historical reasons, `props.class` syntax was invalid once. This required additional efforts to change and this never happened, see https://github.com/facebook/react/pull/10169#issuecomment-320253940 As for me, I wrote `let {className} = props` in React more than once, `class` would be a problem. Zero times in Vue. Can't speak for Svelte. – Estus Flask Mar 11 '20 at 14:22
  • 1
    Svelte doesn't use virtual DOM. – JHeth Mar 12 '20 at 06:31

4 Answers4

5

tldr; JSX (React's language) is a superset of JavaScript (where class is a reserved keyword), while Vue and Svelte both have templating languages which are supersets of HTML, thus allowing the use of class as you would in HTML.


Speaking for Svelte here.

First, let's fix the false premise:

JavaScript frameworks like React and Svelte don't allow developers to use the class property on a virtual DOM element because the class keyword is reserved in JavaScript.

Svelte does allow the class keyword, both on elements and components. You just have to work within the applicable constraints. We're coming back to this.

Let's start with React. Well, JSX actually. JSX is a strict superset of JS. Let's refer to this nice explanation. JSX is a superset of JS both syntactically (any JS program is valid JSX) and semantically (any JS program behaves the same when interpreted as JSX).

In order to be so, JSX has to respect every constraints of JS, of which "class is a reserved keyword". That's why React doesn't allow the class keyword.

Note that this is not a technical constraints. React could reinterpret the class keyword and make it work in JSX. But that would make JSX not strictly a superset of JS. Why? Because then, in some cases, the same JS code would not behave the same when interpreted as pure JS or as JSX (namely, having a variable named class must crash to be JS).

This is a philosophical constraint. At one point, JSX developers must have weighted the inconvenience of not being able to use the class keyword against suddenly not being a strict superset of JS. On one hand, you gain one little nicety, on the other you abruptly downgrade from being a mathematically pure superset to being just "yet another random template language".

It's easy to feel the strong mathematical incline that emanates from React, with its emphasis on pure functions, the "view as a function of the state", unidirectional data flows, etc. This is actually a very important taking from React. They imported a lot of benefits from mathematics into everyday application development. And so, quite understandably (to me), this group of developers favored (favors) purity over minor conveniences.

Being a superset of JS does bring many advantages. Even if you know nothing of JSX, you can write some immediately by using your existing JS knowledge. As long as you don't start using JSX extra features, you can predict all the behaviours of your code, because everything will behave the same.

Now, to the Svelte specifics... Svelte does not use JSX (and neither Vue in most cases, as far as I know). They use their own templating language. Not sure for Vue, but for Svelte it is a superset, not of JS, but of HTML. Rich Harris, creator of Svelte, once called that HTMLX in a talk (not sure how official this terminology currently is). Personally, this is one of the main reason why I'm so comfortable with Svelte. I find it cumbersome to write HTML is JS, while writing natural looking HTML(X) to, in the end, produce HTML feels just... Natural! But I digress...

So, the thing is Svelte too has to play within the limits of its own chosen laws. There are 2 of them that are relevant to the matter at hand. Both makes sense, and both can be worked around.

But first, to clear any misconception, Svelte does allow the use of the class keyword for native elements (as opposed to Svelte components):

<div class="whatever">No problem with that</div>

It wouldn't be a proper superset of HTML if it didn't.

In this context, class is actually a "directive", meaning it has added power, as compared to a pure HTML class. For example:

<script>
  let blue = true
</script>

<!-- will render as: <div class="blue"></div> -->
<div class:blue />

<!-- will render as: <div class="red"></div> -->
<div class:red={blue} />

<!-- you can have several of them too... -->
<div class="foo" class:red class:blue />

So Svelte allows the use of the class keyword, there's no doubt about that. For native elements that is.

Now, for components the story is a bit different. Here come the 2 laws I have mentioned earlier.

The first one is that Svelte components do not enforce having a single root elements. Or any elements at all, for that matter.

<script>
  console.log('I am a valid Svelte component with no elements')
</script>
<!-- no code omitted -->
<p>I am a valid Svelte component</p>
<p>Too.</p>

The consequence of this is that Svelte can't know for sure to what element(s) it should automatically apply a class set on the encompassing component. And so, in this situation, it doesn't do anything. It hands the controls back to you.

That doesn't mean that you can't implement it if you want. You just have to abide by our second law: the code inside the <script> tag of a Svelte component has to be valid JS. Here again, this is not a technical limitation, but a philosophical one. It has been reiterated again and again by Svelte's creator and core developers on many occasions. On the syntax level, we're not even speaking of a superset anymore, but of equality. Any Svelte JS is valid JS (note the members of the relation have been swapped, as compared to "any JS is valid JSX").

On the other hand, Svelte JS is not a semantic superset of JS either. Some JS programs wont behave the same when interpreted as pure JS as when interpreted with Svelte, because Svelte overloads some constructs (like $: or export let prop) with a different meaning.

This constraint impacts us here because class is not a valid variable name is JS, and Svelte components' properties are defined as JS variables. However you can bypass it:

<script>
  // can't do, not valid JS:
  //    export let class

  // but:
  let cls = ''
  export { cls as class } // valid JS
</script>

<div class={class} />

This component would be then used like this (live example):

<script>
  import MyComponent from './MyComponent.svelte'
</script>

<MyComponent class="blue" />

So you can also use the class keyword for components in Svelte.

Phew. Hope you enjoy a developed answer!

To sum it up, if some of the major frameworks allow the use of the class keyword and some don't, it is for philosophical reasons. It makes full sense for JSX, as a superset of JS, to respect this constraint. It would make no sense for Svelte's HTMLX to implement this constraint for no reasons (and to stop being a superset of HTML in the process). Further, React has a stronger focus on mathematics purity, and Svelte has a stronger focus on code expressiveness and convenience. As always with good software, it's all in the trade-off!

Brady Dowling
  • 4,920
  • 3
  • 32
  • 62
rixo
  • 23,815
  • 4
  • 63
  • 68
  • 1
    Thank you for the detailed answer, this was tremendously helpful and informative, exactly what I was looking for. I've crossed out Svelte in my OP and added an edit callout to fix my misinformation. – Brady Dowling Mar 12 '20 at 12:39
0

You can't use class with React because React uses React DOM, which uses camelCase property names, not classical HTML attributes. This is why in JSX (React render language), you have to use className, not class.

Vue is using classical HTML template, so class is allowed.

With Svelte, you should be able to use class keyword in your template.

Zooly
  • 4,736
  • 4
  • 34
  • 54
0

React library uses JSX to render any DOM elements. JSX is a kind of extension for JS to render HTML from javascript. JSX is transpiled before rendering into the browser. Hence className has to be used instead of class. But, there are several advancements taking from one reactjs version to another.

Looks like a similar question is already asked. Find more explanation on class vs className in React 16

user2063635
  • 214
  • 1
  • 10
0

According to my research answers: thanks to their built function.

I found on the side of Vue.js https://github.com/vuejs/vue/blob/dev/dist/vue.js that Vue is binding the class from a JavaScript object to Node. The (vue) node element is used with JavaScript to assign to a DOM elm all classes.

The JavaScript code el.setAttribute('class', cls) is confirming it.

  function transformNode (el, options)

and from this you'll find function at line 5503:

  function genClassForVnode (vnode)

which use the

  function renderClass (staticClass, dynamicClass)

This function is then used by

function updateClass (oldVnode, vnode) {
    var el = vnode.elm;
    var data = vnode.data;
    var oldData = oldVnode.data;
  [...]  
    var cls = genClassForVnode(vnode);

    // handle transition classes
    var transitionClass = el._transitionClasses;
    if (isDef(transitionClass)) {
      cls = concat(cls, stringifyClass(transitionClass));
    }

    // set the class
    if (cls !== el._prevClass) {
      el.setAttribute('class', cls);
      el._prevClass = cls;
    }
  }

note: the following functions are interesting: function addClass(el, cls) line 7873 function bindObjectListeners(data, value) line 2866

Does it helps ?

AymericFi
  • 140
  • 1
  • 8