Skip to content

Instantly share code, notes, and snippets.

@sebmarkbage
Last active October 8, 2024 14:30
Show Gist options
  • Save sebmarkbage/f1f4ba40816e7d7848ad to your computer and use it in GitHub Desktop.
Save sebmarkbage/f1f4ba40816e7d7848ad to your computer and use it in GitHub Desktop.
React JSX - Lower Case

Lower Case JSX Convention

All lower case JSX tags will now be treated as HTML/SVG elements. They will no longer be treated as custom components in scope.

The React element produced by JSX can be either a React class that exists in the local scope or a global scope HTML/SVG element depending on a convention.

Previous Behavior

Currently, when you use React JSX to define a HTML element you can use any known HTML tag. E.g:

return <div />;

This means that we never use the local variable for HTML tags:

var div = React.createClass();
return <div />; // HTML tag, not the custom class

If you use a non-HTML tag we DO use the local variable:

var component = React.createClass();
return <component />; // custom component

The Whitelist Problem

We have a whitelist of HTML tags. This becomes a problem because nobody knows the full list of HTML components. It's also not a static list.

This means that every time there's a new HTML/SVG tag, you can't use it until we add it to the whitelist. You can't add it to the whitelist until you update your existing codebase. For example, we recently added the picture tag. Without a codemod something like this would've broken:

var picture = React.createClass();
return <picture />;

Nobody wants to maintain this whitelist and update their codebase every time it changes.

New Behavior

The new convention is that any JSX identifers that starts with a lower-case characters are assumed to be HTML tag:

var component = React.createClass();
return <component />; // HTML tag, no longer a custom component

This also works with lower camel case:

return <foreignObject />; // SVG tag, not custom component

To access a local variable you'll have to use an upper-case convention:

var Component = React.createClass();
return <Component />; // custom component

This can be inconvenient if your style guide requires you to name classes with lower-case names.

Plausible Alternative 1: Explicit Syntax

We could add some explicit syntax to differentiate between HTML tags and local variables. E.g. we could add string syntax around HTML tags:

return <"div">content</"div">;

However, this no longer looks like HTML which is one of the nice features of JSX. It's quite annoying if you're creating HTML heavy components.

Another alternative would be to wrap custom components in explicit syntax:

return <{Component}>content</{Component}>;

Unfortunately, it is best practice to use a lot of custom components with React. Everything is a component. This starts becoming inconvenient and it's one of the reasons we have JSX instead of just template literals.

The inconvenience seems to be a deal breaker, at least for now.

Plausible Alternative 2: Scope Chain

It's possible that we could check for variables in the currect scope chain (assuming strict mode restrictions of with and eval).

If a local variable is in scope, then we'd use it. Otherwise, we'd assume that HTML is used.

function a() {
  return <picture />; // HTML tag
}

function b() {
  var picture = React.createClass();
  return <picture />; // custom class
}

This could potentially be a refactoring hazard if you accidentally remove a variable and now your JSX starts outputting strange HTML tags.

Additionally, there is some confusing behavior when common variable names overlap with picture elements:

function getListItems() {
  var list = [];
  for (var i = 0; i < 10; i++) {
    // This would end up trying to use the local variable `i`
    // as a custom component:
    list.push(<li><i>Italic Text</i></li>);
  }
  return list;
}

A surprising number of people still use applications with global scope or custom module systems. It would not be possible to use components that exist outside of the local scope chain that our transformer can analyze.

Since this is a tooling nightmare right now, we don't consider this a viable alternative at the moment. It might be possible in the future when build and module systems are better standardized and widespread.

@uatec
Copy link

uatec commented Mar 28, 2016

Yeah. This doesn't actually happen. You get an error linking to this page. e.g. when writing SVG: tags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment