Why component identifiers must be capitalized in React

Post Editor

In this article, we will investigate why component identifiers must be capitalized in React

4 min read
1 comment
post

Why component identifiers must be capitalized in React

In this article, we will investigate why component identifiers must be capitalized in React

post
post
4 min read
1 comment
1 comment

In this short article, I’d like to share some findings as to why a component must be used as <Foo />(capitalized), as opposed to <foo />. It may not occur very often(may not even be recommended), but if you import a component like import foo from './Foo' and use it as <foo />, React will not be happy with that:

Content imageContent image

You can quickly see this in action in this CodeSandbox app.

In other words, <foo /> is considered a DOM element and the foo DOM element does not actually exist, hence the error. Although the fix is straightforward, another thing sparked my interest: how exactly is decided that <Foo /> should be a component and <foo /> a DOM element?

In the rest of the article we will briefly talk about the Babel and then we will reveal the answer to that question.


How Babel works at a high level
Link to this section

As you might know, Babel is the tool responsible, among other things, for converting JSX into syntax which is comprehensible for the browser. It does that through a number of plugins, but the one of interest for now is [@babel/plugin-transform-react-jsx](https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-react-jsx).

Here is a diagram that partially covers the Babel’s compiling process:

UntitledUntitled

The corresponding link for the above diagram can be found here.

So, Babel will take the initial source code as a raw string and then it will build the corresponding AST which all sorts of plugins will be applied on. For example, here we can see the plugin we mentioned earlier, transform-react-jsx:

UntitledUntitled

In the image above, the transformFile function refers to the second phase of the previous diagram - it’s where all the selected plugins are applied on the raw AST.

The way the transform-react-jsx plugin works is that it comes with some functions to be invoked when certain AST nodes are visited. For example, here is what happens when a JSXElement node has been visited:

UntitledUntitled
The exit function can be thought of as a visiting hook. Its complement is the enter function, which is called when a node is about to be visited. After enter, the current AST node’s children are visited and, after that, the exit function is called for that node. To put it another way: Node.enter() → visited children → Node.exit().

In the image above, we are at the <Foo /> part. As you can notice, the JSXElement has an JSXOpeningElement which, for its part, has a name(i.e. JSXIdentifier). What also happens at this step is to decide what really Foo refers to - does it refer to a component or just another DOM element? This decision has to be made because in JSX we can write <div></div>, as well <CustomComponent></CustomComponent> - at some point, Babel has to choose what actually a JSXElement is and, later on, React will react accordingly.

Calling JSXElement.exit() will eventually lead to calling the getTag function, which is the place where the question stated at the beginning finds its answer:

UntitledUntitled

The getTag function will return a string literal(e.g. “div”, “foo” if used as <foo />) if the tagName starts with a lowercase letter(i.e. /^[a-z]/). So, if <Foo /> is used, the result will be:

<>Copy
{ type: "Identifier", start: 165, end: 168, name: "Foo", /* ... */ }

and, on the other hand, if <foo /> is used:

<>Copy
{ type: "StringLiteral", value: 'foo', }

The fundamental difference between an Identifier and a StringLiteral is that the former will end up in createElement(componentName) and the latter in createElement('componentName')(take note of the quotes). React will then choose different paths depending on the element’s type.


Conclusion
Link to this section

Before starting to explore some of the things that Babel does under the hood, I had expected that there must be a check somewhere that indicates whether JSXElement actually refers to a component identifier or not, but I had not idea where that check was located.

In the end, the answer to my question turned out to be the isCompatTag function. Even if I had known this beforehand, I would’ve needed some more context about that function - so, exploring a bit how Babel works not only made things more clearer to me, but also exposed me to other interesting aspects of the entire compiling process(which I will hopefully write about in the future).

Thanks for reading!

Comments (1)

authorDmitryMorlender
18 May 2022

Very interesting, thank you!

authorAndrei0872
21 May 2022

I'm glad to hear that, @DmitryMorlender! Thank you!

Share

About the author

author_image

A curious software developer with a passion for solving problems and learning new things.

author_image

About the author

Andrei Gatej

A curious software developer with a passion for solving problems and learning new things.

About the author

author_image

A curious software developer with a passion for solving problems and learning new things.

Looking for a JS job?
Job logo
React Native Developer

Talent Group

Worldwide
Remote
$100k - $150k
Job logo
React Native Lead Developer

fuge technologies

Worldwide
Remote
$119k - $151k
Job logo
React Developer

NTERSOL

Worldwide
Remote
$85k - $160k
Job logo
Senior BI Developer with React / RoR / Python Experience

fraction

United States
Remote
$120k - $180k
More jobs
NxReactCli
NxReactCli
NxReactCli

Featured articles

blockchainpost
19 July 202212 min read
An Introduction to Blockchain

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

blockchainpost
19 July 202212 min read
An Introduction to Blockchain

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

Read more
blockchainpostAn Introduction to Blockchain

19 July 2022

12 min read

Learn the fundamentals of a blockchain starting from first principles. We'll cover hashing, mining, consensus and more. After reading this article, you'll have a solid foundation upon which to explore platforms like Ethereum and Solana.

Read more