jsx
jsx copied to clipboard
RFC: JSX shorthand attributes
Support shorthand syntax for passing variables as props, where the variable name is same as the prop name; similar to the shorthand properties in ES6 object literals.
For example : <Component prop1={prop1} prop2={prop2} /> can be written as <Component +prop1 +prop2 /> using the shorthand syntax.
This RFC was originally put on reactjs/rfcs. Here is the relevant PR for that. The full text of the RFC is given below.
Summary
Provide a shorthand syntax for passing variables as props, where the variable name is same as the prop name; similar to the shorthand properties in ES6 object literals.
Basic example
function Toggle ({ onChange, checked, className }) {
const toggleClasses = classd`checkbox-toggle ${checked && 'active'} ${className}`;
function onClick () {
onChange(!checked);
}
return <input type='checkbox' className={toggleClasses} +onClick +checked />;
}
This snippet transpiles to
function Toggle ({ onChange, checked, className }) {
const toggleClasses = classd`checkbox-toggle ${checked && 'active'} ${className}`;
function onClick () {
onChange(!checked);
}
return <input
type='checkbox'
className={toggleClasses}
onClick={onClick}
checked={checked} />;
}
Motivation
While using react, it happens quite a number of times that we need to:
i. pass a prop down the component chain with the same name ii. pass a variable / function with the same name as the prop
In such cases, we need to write the same name twice as propName={propName}
. This
is redundant. Also with the increase in the use of function components and
useState hooks, the usecase for such props is ever increasing.
Providing a shorthand syntax for passing such props would make the code concise and encourage developers to write cleaner and less redundant code.
Detailed design
The shorthand syntax, +propName
(as recommended in this RFC) is to be supported
by existing JSX transpilers. It can be done by updating the parse and transform functions
for JSXAttribute
nodes.
NOTE. This design is intended to work only with JSXIdentifier
nodes prefixed with
+
in the JSXAttribute.name
field. It should not work with JSXNamespacedName
and
should throw an Unexpected Syntax Error
otherwise.
In parseJSXAttribute
- check is the Token starts with a
+
, i.e.charCodes.plusSign (ascii, 43)
- if true:
i. eat the
tokens.plusMin
Token. ii. start aJSXAttribute
Nodenode
. iii. callparseJSXIdentifier
and setnode.name
andnode.value
to the parsedJSXIdentifier
. iv. finish and returnnode
- otherwise continue with the existing
parseJSXAttribute
logic.
In transformJSXAttribute
visitor (entry phase)
- Check if the value in the current node (
path.node.value
) is aJSXIdentifier
. - If true, set the value in the current node (
path.node.value
) to aJSXExpressionContainer
containing anIdentifier
with the name same as the name of theJSXIdentifier
. i.e.types.jsxExpressionContainer(types.Identifier(path.node.value.name))
and return. - Otherwise continue with the existing visitor logic.
Drawbacks
- It goes against the principle "There should be one-- and preferably only one --obvious way of doing it". With the introduction of shorthand attributes, the way of writing JSX attributes becomes 4:
- The Standard
<Component propName={expr} />
- Spread attributes
<Component {...props } />
- Boolean attributes
<Component booleanProp />
- Shorthand attributes
<Component +prop1 +prop2 />
- The Standard
- There may be confusion with boolean attributes, the syntactic difference being only the
+
prefix. - This proposes adding a new/different semantics to the existing unary
+
operator, even though this addional semantics is valid only within the context ofJSXAttributes
Nodes.
Alternatives
- Maintaining the status quo, i.e. requiring the propName and the propValue to be written explicitly.
- Using any other symbol than
+
as the prefix, so that we do not add to semantics of existing operators. maybe@
.
Adoption strategy
This is not a breaking change and does not require any change to the codebase of React itself. It needs to be implemented by JSX transpilers and can be made available with their release cycle. Create-react-app, react-scripts, Linters and other existing tools need to support use of newer version of the JSX transpiler (plugin).
Existing react projects will still be valid with the newer syntax without requiring any change. But
styleguides and linters can provide the options like --allow-jsx-shorthand-attributes
to process
the newer syntax as valid, and --use-jsx-shorthand-attributes
to convert existing code to use
the shorthand syntax where applicable.
How we teach this
If accepted, the shorthand syntax can be specified and taught in the React/JSX documentation.
Conceptually using this shorthand syntax is optional, just like using <> </>
for Fragments.
The teaching strategy, therefore, can be similar to that of the Fragments shorthand.
Using +
seems confusing; as +identifier
coerces to a number in JS contexts.
@ljharb what if we use any other symbol than +
as the prefix, so that we do not add to semantics of existing js operators ? maybe @
or &
. &
does not have any associated semantics as an unary operator / prefix.
True, but <a b &c>
does, because b &c
is a bitwise operation in JS.
As for @
, since that's effectively reserved for decorators, I'd suggest avoiding that as well.
The only syntax I'm aware of that doesn't have conflicting conceptual overload is <a b {c}>
.
True, but
<a b &c>
does, becauseb &c
is a bitwise operation in JS.As for
@
, since that's effectively reserved for decorators, I'd suggest avoiding that as well.The only syntax I'm aware of that doesn't have conflicting conceptual overload is
<a b {c}>
.
@ljharb , yes, that's possibly valid for all symbols with binary operator semantics. <a b {c}>
does not have conflicting conceptual overload, but would not it be unusual to allow expressions within braces in almost all contexts in JSX, except for attributes ? In case of shorthand attributes with the syntax <a {c}>
, the only valid expression type for c
is Identifier. But in case of <a b={c}>
, c
can be any valid expression.
Though, in case of JSXSpreadAttributes, we are already limiting the possible types of expressions within the braces {}
. I suppose that's quite an exceptional case.
What about plain ES shorthand notation, which already works? 🙃
<input {...{ disabled, onClick }} />
as a heavy react/jsx user, this feature looks awesome, to say the least. please, please approve it relevant: https://stackoverflow.com/questions/64700558/most-concise-way-to-pass-props-to-a-react-component
What about plain ES shorthand notation, which already works? upside_down_face
<input {...{ disabled, onClick }} />
I prefer this a lot. It's more in line with existing JS syntax (because it just is JS syntax). But the syntax I'd suggest would just be the syntax suggested in #23
return <input {disabled} {onClick} type="button" />
This does more closely resemble JS syntax being reminiscent of shorthand properties on objects. In fact it could even be compiled to exactly that:
return React.createElement("input", { disabled, onClick, type: "button" });