Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: JSX shorthand attributes #121

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

GnsP
Copy link

@GnsP GnsP commented Sep 5, 2019

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 : 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

  1. check is the Token starts with a +, i.e. charCodes.plusSign (ascii, 43)
  2. if true:
    i. eat the tokens.plusMin Token.
    ii. start a JSXAttribute Node node.
    iii. call parseJSXIdentifier and set node.name and node.value to the parsed JSXIdentifier.
    iv. finish and return node
  3. otherwise continue with the existing parseJSXAttribute logic.

In transformJSXAttribute visitor (entry phase)

  1. Check if the value in the current node (path.node.value) is a JSXIdentifier.
  2. If true, set the value in the current node (path.node.value) to a JSXExpressionContainer containing an Identifier with the name same as the name of the JSXIdentifier. i.e. types.jsxExpressionContainer(types.Identifier(path.node.value.name)) and return.
  3. 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:
    1. The Standard <Component propName={expr} />
    2. Spread attributes <Component {...props } />
    3. Boolean attributes <Component booleanProp />
    4. Shorthand attributes <Component +prop1 +prop2 />
  • 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 of JSXAttributes 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.

@ljharb
Copy link

ljharb commented Sep 6, 2019

Using + seems confusing; as +identifier coerces to a number in JS contexts.

@GnsP
Copy link
Author

GnsP commented Sep 6, 2019

@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.

@ljharb
Copy link

ljharb commented Sep 6, 2019

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}>.

@GnsP
Copy link
Author

GnsP commented Sep 6, 2019

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}>.

@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.

@GnsP
Copy link
Author

GnsP commented Sep 6, 2019

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.

@asbjornh
Copy link

What about plain ES shorthand notation, which already works? 🙃

<input {...{ disabled, onClick }} />

@yigalirani
Copy link

yigalirani commented Nov 5, 2020

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

@QbDesu
Copy link

QbDesu commented Oct 16, 2021

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" });

@Huxpro Huxpro added Component: Attribute Proposal 2.0 Proposals considerable for JSX 2.0 and removed Proposal 2.0 Proposals considerable for JSX 2.0 labels Feb 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants