Giter Site home page Giter Site logo

jsx's Introduction

DRAFT: JSX Specification

Support Ukraine

See spec text with grammar here.

JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It's NOT intended to be implemented by engines or browsers. It's NOT a proposal to incorporate JSX into the ECMAScript spec itself. It's intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.

// Using JSX to express UI components.
var dropdown =
  <Dropdown>
    A dropdown list
    <Menu>
      <MenuItem>Do Something</MenuItem>
      <MenuItem>Do Something Fun!</MenuItem>
      <MenuItem>Do Something Else</MenuItem>
    </Menu>
  </Dropdown>;

render(dropdown);

Rationale

The purpose of this specification is to define a concise and familiar syntax for defining tree structures with attributes. A generic but well defined syntax enables a community of independent parsers and syntax highlighters to conform to a single specification.

Embedding a new syntax in an existing language is a risky venture. Other syntax implementors or the existing language may introduce another incompatible syntax extension.

Through a stand-alone specification, we make it easier for implementors of other syntax extensions to consider JSX when designing their own syntax. This will hopefully allow various new syntax extensions to co-exist.

It is our intention to claim minimal syntactic real estate while keeping the syntax concise and familiar. That way we leave the door open for other extensions.

This specification does not attempt to comply with any XML or HTML specification. JSX is designed as an ECMAScript feature and the similarity to XML is only for familiarity.

Why not Template Literals?

ECMAScript 6th Edition (ECMA-262) introduces template literals which are intended to be used for embedding DSL in ECMAScript. Why not just use that instead of inventing a syntax that's not part of ECMAScript?

Template literals work well for long embedded DSLs. Unfortunately the syntax noise is substantial when you exit in and out of embedded arbitrary ECMAScript expressions with identifiers in scope.

// Template Literals
var box = jsx`
  <${Box}>
    ${
      shouldShowAnswer(user) ?
      jsx`<${Answer} value=${false}>no</${Answer}>` :
      jsx`
        <${Box.Comment}>
         Text Content
        </${Box.Comment}>
      `
    }
  </${Box}>
`;

It would be possible to use template literals as a syntactic entry point and change the semantics inside the template literal to allow embedded scripts that can be evaluated in scope:

// Template Literals with embedded JSX
var box = jsx`
  <Box>
    {
      shouldShowAnswer(user) ?
      <Answer value={false}>no</Answer> :
      <Box.Comment>
         Text Content
      </Box.Comment>
    }
  </Box>
`;

However, this would lead to further divergence. Tooling that is built around the assumptions imposed by template literals wouldn't work. It would undermine the meaning of template literals. It would be necessary to define how JSX behaves within the rest of the ECMAScript grammar within the template literal anyway.

Therefore it's better to introduce JSX as an entirely new type of PrimaryExpression:

// JSX
var box =
  <Box>
    {
      shouldShowAnswer(user) ?
      <Answer value={false}>no</Answer> :
      <Box.Comment>
         Text Content
      </Box.Comment>
    }
  </Box>;

Why not JXON?

Another alternative would be to use object initializers (similar to JXON). Unfortunately, the balanced braces do not give great syntactic hints for where an element starts and ends in large trees. Balanced named tags is a critical syntactic feature of the XML-style notation.

Prior Art

The JSX syntax is similar to the E4X Specification (ECMA-357). E4X is a deprecated specification with deep reaching semantic meaning. JSX partially overlaps with a tiny subset of the E4X syntax. However, JSX has no relation to the E4X specification.

Contributing

The main purpose of this repository is to continue evolving JSX. We are grateful to the community for contributing bugfixes and improvements.

Meta has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.

Read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to JSX.

License

Copyright (c) 2014 - present, Meta Platform, Inc. All rights reserved.

This work is licensed under a Creative Commons Attribution 4.0 International License.

jsx's People

Contributors

adrianheine avatar allanrenucci avatar amasad avatar amsardesai avatar army8735 avatar calebmer avatar clemmy avatar dmitryvinn avatar dmitryvinn-fb avatar facebook-github-bot avatar huxpro avatar jack-works avatar jmm avatar josh-cena avatar kuraga avatar poziworld avatar rreverser avatar sebmarkbage avatar soda0289 avatar sophiebits avatar syranide avatar theel0ja avatar vjeux avatar zetachang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsx's Issues

Custom attribute namespace

React has two special features in JSX that others might not want. Namely key and ref attributes are treated as special cases. This might go a long way to unifying the semantic meaning as well.

We could namespace such attributes with either a name or symbol. A name might be bloated and a name might be too involved.

<Foo @key="foo" @ref={callback} prop="hi" />
<Foo :key="foo" :ref={callback} prop="hi" />
<Foo #key="foo" #ref={callback} prop="hi" />
<Foo react:key="foo" react:ref={callback} prop="hi" />

Document white-space behavior?

The white-space behavior of JSX is quite important to React and probably makes a lot of sense from a JS-perspective where the content of strings are tightly controlled. Encoding all white-space as-is would add significant useless overhead to generated output and the way you structure your code would affect the output (which is really bad IMHO).

Do we have to document it? Not really, but it could make sense (especially for inter-op).

Another thing worth considering is what we want to do with intentional leading/tailing whitespace, currently you have to do &#40; (or {' '} if you don't care about split children), it is not actually supported by JSX at the moment, but it will be. Perhaps there are better solutions? Something like {+' '}, {+' '+}, etc?

Feel free to glance at facebook/react#480 for my research/decisions for the current white-space rules (my "dense language" may not make it easy though, but I'd gladly explain it all if necessary).

PS. I feel like dropping the "tabs to spaces" I decided on for JSX, it makes some sense, but it's also kind arbitrary (what about vertical tabs, etc, etc).

[IDEA] Multiple library targets.

JSX was designed for writing things like

<ul>
    <li></li>
    <li></li>
</ul>

and converting them into JavaScript like

React.DOM.ul(null, [
    React.DOM.li(null, []),
    React.DOM.li(null, []),
])

Is there anything in the spec about using JSX with different functions for different parts of the tree, and some way to define how to connect those parts of the tree? Maybe it's be some class like JSXAdapter needing to be provided by someone when they wish to switch control of the tree from React to Mithril for example.

Suppose I have a custom renderer made in WebGL called Foo, and I'd love for React users to write declarative scene graphs with Foo. I know that I can just go ahead and use the React API to create components that construct and manipulate a Foo scene graph (and by extension we can now use JSX to write a Foo scene graph), but that isn't compatible with Mithril, Mercury, etc.

Suppose this Foo library has a JSX-compatible functional design, so that it's possible to do this with Foo:

Foo.scene(null, [
    Foo.someThing(null, []),
    Foo.otherThing(null, []),
])

It's not too hard to make JSX compile to a different underlying set of function calls. On that note, it'd be nice if there were some way to connect different UI structures together, as in the following JSX example:

<div>
  <main>
    <Foo.scene>
      <Foo.someThing>
         ...
      </Foo.someThing>
    </Foo.scene>
  </main>
</div>

The underlying function calls could transition from React functions to Foo functions, based on some runtime configuration, where some sort of adapters are specified that tell the runtime how to connect the parts of the tree together. Underneath the hood in some cases, the div and main might be React components, and the inner parts Foo components. In other cases, the div and main might be Mithril components, or Mercury, or etc, while the inner ones are still Foo components.

Does anything like that exist? If not, I think that would be amazing to have, and could potentially open the doors towards easier integration between UI libraries, as described here.

Crazy Idea: Deprecate JSXText?

Currently we allow arbitrary text content to flow amongst tags. However, we have noticed that while building UIs, you actually don't utilize this very much. @syranide can speak more to this.

You usually want to wrap your text content in some other container. E.g. instead of writing it like this:

<div> Foo <Button /> </div>

You should write something like this:

<div> <Label text="Foo" /> <Button /> </div>

At the very least you want to wrap it for internationalization purposes:

<div> <Intl message="Foo" desc="A label" /> <Button /> </div>

What if we only treated it as a sequence of expressions and got rid of the curlies? We don't really need curlies around attributes since they can disambiguated with parenthesis if necessary.

That way the JSX example would become:

var box =
  <Box>
      shouldShowAnswer(user) ?
      <Answer value=false>"no"</Answer> :
      <Box.Comment>
         "Text Content"
      </Box.Comment>
  </Box>;

No curlies!

Multiple JSXChildren have to be delimitated by ,. A JSX elements doesn't need to be followed by a comma.

var box =
  <Box>
      "Leading text",
      functionCall(),
      <Answer value={'this is': 'an object'}>"yes"</Answer>
      <Box.Comment><Child /></Box.Comment>
      anotherFunctionCall(),
      <OptionalTrailingComma />,
      (expr + ession)
  </Box>;

This moves the design further away from HTML generation and towards UI composition.

How can we change the expression delimiters for some of our components?

How can we change the javascript expression delimiters?

For now JSX uses { and } as expression delimiters, but how could we change this delimiters for some of our components? For example, how could we write expressions like ${ 1+1 } or {{ 1+1 }} instead of { 1+ 1}?

The main motivation for this is to use the power of JSX to not just create powerfull HTML-JS-like components but to create CSS-JS-like components too.

For example, I wrote this example in codepen:

function Style(props) {
  return <div>
    <h1>
      {props.children}
    </h1>
    <style>
      {props.children}
      h1 {'{'}
        color: {props.color};
      {'{'}
    </style>
  </div>;
}

ReactDOM.render(
  <Style
    color="white"
  >
    * {'{'}
      background-color: red;
    {'}'}
  </Style>,
  document.getElementById('root')
);

This works fine and it's awesome. I think we can create very interesting things with this strategy, for example, do several complex calculations to achive some powerfull style that even css or scss (for example) can't give it to us. We can use the full power of javascript to write our styles if we need this.

But this example will be more readable if JSX just have a little new option to parse expressions using another delimiters like the listed ones above. For example, we could write the same code like this:

function Style(props) {
  return <div>
    <h1>
      ${props.children}
    </h1>
    <style>
      ${props.children}
      h1 {
        color: ${props.color};
      }
    </style>
  </div>;
}

ReactDOM.render(
  <Style
    color="white"
  >
    * {
      background-color: red;
    }
  </Style>,
  document.getElementById('root')
);

So, how can we change the expression delimiters?
Or how can we extend JSX to have this behavior for some special of our components (like Style above)?

Allow for . in attribute names

I would like if . was allowed in attribute names, like this:

<tag-name some.attribute="value" />

which would be transformed into (using react)

React.createElement("tag-name", { "some.attribute": foo });

It's allowed in HTML to have attributes with dots in them.

Template Strings Without Braces

Usually to use template strings, you’d have to wrap it in braces. Since template strings return strings, could we instead have:

<div className=`string-${localVariable}` />

support object literal property value shorthand

side note : following the issue facebook/react/issues/2536

what I'd like to be able to do with jsx is this :

{this.state.list.map((item, key) => <MyComponent {item, key} />)}

I know it's not to be considered a big syntax issue, its just sugar, but it seems logical to me that after supporting the spread operator, as this other ES6 feature is supported by jstransform/jsx

as @sebmarkbage said in the related react issue, the <Foo item /> syntax is supported for boolean attributes, but IMO

var item = "value"
return <Foo {item}/>

isn't that confusing as it is going to get supported by various browsers soon, and developers will have to know it.

so now, I think it's all about discussing this proposal 😄

AssignmentExpression in JSXAttributeName

It would be good to have ability to evaluate attribute name. For example:

<Component {attr}="value" />

Might be transpiled to:

Component({
  [attr]: "value"
});

Yes, this is es6 output because JSX spec extends es6 specs. Transpilers/targets which do not support es6, but only es5 might choose to not support this feature. But for others it might be useful.

Also, E4X support this feature and for me, it's reasonable to have it.

(Breaking) Feature Request: Make JSX even more like JS

I think it is time to make JSX even more like JS and less like HTML. Consider the following JSX:

const name = "Kasper";
const message = <p>Hello, {name}!</p>;
const container = <div>{element}</div>;

What about writing it like this:

const name = "Kasper";
const message = <h1>"Hello, ${name}!"</h1>;
const container = <div>message</div>;

My main subjective reason is that it just looks more right to me. A more objective reason would be that you could introduce javascript comment syntax:

const name = "Kasper";
const message = <h1>"Hello, ${name}!"</h1>;
const container = ( 
  <div>
    // we currently only message the first name
    message
  </div>
);

Similar things could be done for jsx attributes. Instead of:

const element = <Counter count={0}/>;
const element2 = <img src={user.avatarUrl}/>;
const element3 = <div className="header"></div>

I would like it as:

const element = <Counter count=0/>;
const element2 = <img src=user.avatarUrl/>;
const element3 = <div className="header"/>;

Or even better, (I haven't put much thought in this):

const element = <Counter count: 0/>;
const element2 = <img src: user.avatarUrl/>;
const element3 = <div className: "header"/>;

More generally:

<Component
  bool: true,
  num: 1,
  string: "bar",
  expr: x + y,
  valueByPropName,
  ...spreadObject
/>

Inspiration comes from:
https://twitter.com/emilpersson/status/795640485683560449

By just making the syntax more close to javascript, I think many long-standing problems would be more easily fixed:

  • #23 - support object literal property value shorthand
  • #25, #51, #64 - Drop the need for curlies around attribute values if they're a single literal, or parenthesis.
  • #35 - Drop implicit text content and curlies as children.
  • #7 - Extend JSXText with Comment?

Extend JSXText with Comment?

It may be worth extending JSXText with a case for Comment. In a way it's a bit weird as it is technically as if the comment in 'abc/*def*/ghi' would actually work. But practically, I think it makes sense, commenting out JSXElements is currently quite unintuitive/hacky as you have to write:

<compa>
  {/*This text should not be printed: */} value
  <compb>
    {//<compc></compc>} -- actually broken right now IIRC
  </compb>
</compa>

Note that comments actually affect (split) the children too, rather than being transparent. I'm proposing extending the syntax to support the following:

<compa>
  /*This text should not be printed: */ value
  <compb>
    //<compc></compc>
  </compb>
</compa>

As I mentioned, it is a bit weird in a way but still rather intuitive and useful, especially in the sense of having JSX feel like a true extension of JS and not just sugar. I think there is little to lose here; /*, */ and // are unlikely to occur in text, if they do then HTML-entities or JS-escaping (#4) to the rescue. Or if you don't care about children {'/*'} (half-related #6, leading/tailing whitespace).

Consider including difference between <tag> and <Component> in spec

This arose in relation to eslint/eslint#1911

Currently, the spec has a single node type for JSXElementName, which separates three cases: identifier, xml-namespaced identifier, JS member expression identifier.

In the implementation as of 0.12, the semantics of a tag differ depending on the casing of the first character of the identifier.

Could this be incorporated in some way? Perhaps as JSXComponent vs JSXIdentifier or JSXIdentifier vs JSXTag. Something to indicate that one should be interpreted as a variable reference, and one as a string literal.

Proposal: Need of some MVC architecture.

The rendering javascript with the HTML is too complex. And classes are too complex with the many methods. If we have annotations, like initialization of the application. Run time props injections.
Also accessibility support. Key event support @click, @keydown, @load, @render, @mount, @unmount, @component, @model and etc.

In the rendering of component call many times of render() method, It needs some lazy rendering technique which can calculate all change after that it apply in render().
Binding state to props is also a very bad approach

JSX 2.0

We have accumulated a number of these nice-to-haves breaking changes that would be nice to incorporate. However, at this point JSX is a hugely adopted syntax in all kinds of tooling. Making breaking changes will churn that ecosystem significantly. I think it is probably only worth doing as a batch when the accumulated amount of changes makes it worth while.

Let's call it JSX 2.0.

What should go into it?

Since a completely incompatible version of JSX has landed in Reason it would be good to find a way to unify them.

I'd say at least we'd want:

  • #4 - Drop HTML encoding in text and attributes.
  • #21 - Computed attribute names.
  • #23 - Object short hand notation.
  • #25, #51, #64 - Drop the need for curlies around attribute values if they're a single literal, or parenthesis.

Some more controversial/problematic ones that could plausibly be fixed:

  • #39 - Implicit do expressions.
  • #35 - Drop implicit text content and curlies as children.
  • #66 - Custom attribute namespaces.

What else?

cc @jordwalke @SanderSpies

Binding Syntax

Report duplicated at facebook/react#3090

I noticed that the new version of react will require manual binding. This problem will be lessened with ES7, but will still be there. I want to recommend an extension to the JSX language to bind functions to the scope: => over = (akin to arrow functions).

<button onClick=>{ this.onClick }>Submit</button>

Proposal: destructuring

Let's say you have a function that returns an object with a known shape that you want to use as props. Currently with JSX, you would use spread:

<Foo {...bar()} />

This is compiled to the following:

React.createElement(Foo, bar());

Great! Now, let's say you want to add some other props to this.

<Foo {...bar()} baz />

When compiling for React, this is compiled to the following:

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

React.createElement(Foo, _extends({}, bar(), { baz: true }));

Which makes sense, but the Object.assign and _extends helper code here is a bit of a bummer if you happen to do this all over the place. Granted, there are ways to minimize the helper code, but you still have the overhead of Object.assign.

It might be nice to have a way to destructure in JSX to avoid this overhead. Here's an idea:

<Foo {fizz, buzz}={bar()} baz />

could compile to something like this:

React.createElement(Foo, (_bar = bar(), { fizz: _bar.fizz, buzz: _bar.buzz, baz: true }));

JSPerf: https://jsperf.com/object-assign-vs-shenanigans/1

This might dovetail well with AssignmentExpression in JSXAttributeName (#21) which is being considered for JSX 2.0 (#65).

Newlines as whitespace text

Currently contents like

<b>{this.title}</b> <span>123</span>

are converted to

React.DOM.b(null, this.title), " ", React.DOM.span(null, "123")

which is logical and expected since whitespace might change the layout (i.e. inside element with white-space: pre and in other cases).

However:

<pre>
    <b>{this.title}</b> <span>123</span>
</pre>

is converted to

React.DOM.pre(null, 
    React.DOM.b(null, this.title), " ", React.DOM.span(null, "123")
)

so whitespaces across newlines are inserted only in code, but not treated as regular text, which means we loose them completely in generated layout.

Shouldn't we treat them as text too?

JSX Compiler interpolation alternatives.

This will likely never change as it is far too late but it bothers me so I want to at least mention it.

I think that using curlies "{}" for interpolation inside JSX is confusing, unintuitive and ugly. Typically curlies refer to an object or a block neither of which can actually exist inside the interpolation within JSX.

Parens "()" are typically used to enclose an expression which is exactly what is going on in JSX.

I propose that we switch from this:

<div a={ { b: 1 } }/>

Which is confusing for beginners because it looks like an object in an object, or if you are coming from mustache something different entirely.

To:

<div a=( { b: 1 } )/>

Here it would be easy to explain that, like everywhere else in javascript, parans are used to represent an expression which in this case returns an object to the attribute of the virtual div.

Just my thoughts, feel free to discuss or close.


This was originally posted here: https://phabricator.babeljs.io/T7074

Alternative syntax for passing JSX content to props

Silly (but succinct) example:

const If = ({test, yes, no}) => test ? yes : no;

Today we can say this:

const eg1 = (
    <If test={allowed}
        yes={
            <button>Launch missiles</button>
        }
        no={
            <span>Access denied</span>
        } />
);

Proposal is to support this alternative, inspired by XAML:

const eg2 = (
    <If test={allowed}>
        <If.yes>
            <button>Launch missiles</button>
        </If.yes>
        <If.no>
            <span>Access denied</span>
        </If.no>
    </If>
)

In short, if an element name contains . and the first part is the parent element's name, the second part is a prop name and the content becomes the value passed to that prop. Nothing else changes - it's merely an alternative way to specify the prop value.

It remains consistent with XML, where . is allowed; indeed, XAML was forced to do this in order to be an XML dialect and yet be flexible about how properties are specified on objects. JSX doesn't have that challenge, nevertheless in more complex examples it would lessen brain- and eye-strain to keep the structure of the tree obvious by staying in JSX syntax instead of { ... } blocks stretching across many lines, and with a few layers of nesting alternating syntaxes.

And a further enhancement, say we have:

const For = ({items, each}) => <div>{items.map(each)} </div>

Today we can say this:

const eg3 = (
    <ul>
        <For items={things} 
            each={item => (
                <li>{item}</li>
            )} />
    </ul>
);

But how about:

const eg4 = (
    <ul>
        <For items={things}>
            <For.each item>
                <li>{item}</li>
            </For.each>
        </For>
    </ul>
);

That is, in these "prop elements", which have no other purpose for their attributes, they can optionally specify valueless attributes. These become the parameter names of a function, and that function is then is passed to the prop. (Once again, it maps exactly to the previous example.) If no attributes are specified, as in eg2, then there is nothing variable for the content to depend on and hence it can just be a simple value rather than a function returning a value.

I found a prior issue facebook/react#848 that seemed to be asking for something similar but wasn't as precisely mapped to existing concepts. Here I'm not talking about anything that changes the model, just a way of staying in JSX and reducing the mental overload of switching syntaxes when writing/reading trees.

Document parsing of (X)HTML entities, or drop it even?

We should probably document how (X)HTML entities are parsed.

However, I can imagine dropping HTML entities instead and adopt the escaping used by JS-strings, i.e. bla \< \{ \u1234 bla. To me it would make sense in many ways:

  1. JSX is the JavaScript-equivalent of HTML (it's not HTML), using JavaScript syntax seems preferable.
  2. JSX explicitly disallows inline HTML in-favor of just JSXElements and JSXText, HTML entities seem a bit malplaced in that context.
  3. It's currently <a href="&amp;\" /> vs <a href={'&\\'} /> which is kind of awkward.

The downside of dropping HTML entities is obviously that you wouldn't be able to copy-paste HTML and it could be a mental disconnect for a lot of users. But I think it makes a lot of sense from a technical perspective.

I think it makes even more sense if you look beyond HTML. Why would you be using HTML entities for non-HTML frontends? Like iOS, QT, etc.

Proposal: allow "nameless" elements to represent plain objects

Example:

const sharedProps = <
  type='button'
  style={{ background: 'red', color: 'white' }}
/>;

const buttonElement = <button 
  {...sharedProps}
  onClick={doSomething} 
/>;

const anotherButtonElement = <button 
  {...sharedProps} 
  onClick={doSomethingElse} 
/>;

The main purpose for allowing this would be to ease refactoring. If you wish to pull out props into an object, currently you have to change prop={value} to prop: value, for all of them. The syntax above allows simple cut-and-paste.

Making JSX more like JS would accomplish the same goal, but this seems less drastic.

Edit: OK, so this might be problematic because spaces are currently allowed between < and the tag name. I just never noticed because I never write it that way. Regardless, some sort of JSX object declaration syntax would be nice.

Support numeric attribute values

It seems like such an obvious thing, but is there a specific reason why we still don't support <Foo bar=2 />? It is trivial to support and it would make it more natural to provide numbers where numbers are expected.

Spec proposal: extending the language to allow spreading children

I propose we modify the JSX specification to allow for the spreading of child nodes in JSX like so:

<div>{...children}</div>

Instead of the implicit array flattening done by React and other JSX consumers currently.

Rationale

JSX with React allows you to do this:

const TodoList = ({ todos }) => (
  <div>
    {todos.map(todo => <Todo key={todo.id} todo={todo}/>)}
  </div>
)

However, React cleverly hides what is actually happening. If we turn the above JSX into a static object, we get something that looks like this:

const TodoList = ({ todos }) => ({
  type: 'div',
  children: [
    todos.map(todo => )
  ],
})

As you can see we have a nested array:

[todos.map(todo => )]

This requires JSX consumers to flatten arrays before processing them. A step that is not only unnecessary but also difficult to express in a JSX type system that would otherwise look like a tree.

type JSXNode = JSXNodePrimitive | JSXElement

Must instead become something to the effects of:

type JSXNode = JSXNodePrimitive | JSXElement | Iterable<JSXNode>

It’s strange that we should have this problem, however, when the solution should really be in the language. Already ES6 has introduced the spread operator (...), so modifying our above example to:

const TodoList = ({ todos }) => ({
  type: 'div',
  children: [
    ...todos.map(todo => )
  ],
})

Will give us the list of list of children the JSX consumer needs without requiring a post processing step. We add the expressiveness to the language and we remove complexity from our JSX consuming libraries (like React).

In order to add this extension, we just extend JSXChild to allow for the type { ... AssignmentExpression(opt) }.

Then the above example would become:

const TodoList = ({ todos }) => (
  <div>
    {...todos.map(todo => <Todo key={todo.id} todo={todo}/>)}
  </div>
)

Or the classic children example would be:

<div>{...children}</div>

And this would compile to a form we expect at a type level:

{
  kind: 'div',
  children: [
    ...children,
  ],
}

Motivation

React isn’t the only library/framework which should be able to consume JSX, and we shouldn’t expect every library/framework to adopt React’s JSX “workaround” of flattening child arrays when in fact that is a fault in the language extension.

Therefore, in order to simplify libraries and avoid extra complexity in JSX consumers we should implement this proposal.

Next Steps

I wanted to submit this proposal here to see if anyone had opinions on it before I started writing code. In the near future I will probably submit a PR to the Babel repository modifying the babel-plugin-syntax-jsx plugin adding this change. After that PR I will implement a transform in my general JSX transformation library babel-plugin-transform-jsx. If both experiments are successful we can consider adding the child spread functionality to the JSX spec and other JSX transpilers.

Thanks!

Support component class expressions

I would like JSX to support higher order components (e.g. functions that take and return components).

For example, given a component UserPortrait and a higher-order component ImageDropTarget (that wraps drag-and-drop image uploading around a component) I would like to be able to combine the two inline in the JSX for my UI, like so:

<ImageDropTarget(UserPortrait) src="blah-blah" onDrop={blah blah}/>

At the moment, one has to define temporary variables to use higher order components from within JSX. E.g.

var ImageDropTargetUserPortrait = ImageDropTarget(UserPortrait);
...
<ImageDropTargetUserPortrait  src="blah-blah" onDrop={blah blah}/>

JSX Spread tag proposal

This is a feature request.

It is a common request from developers to allow returning multiple elements from inline expressions in JSX.

http://stackoverflow.com/questions/23840997/how-to-return-multiple-lines-jsx-in-another-return-statement-in-react

A use case for this would be this pseudocode:

<Parent>{ flag ? <Child/> : <Sibling1/><Sibling2/><Sibling3/>}</Parent>

which would have React generate either <Parent><Child/></Parent> or <Parent><Sibling1/><Sibling2/><Sibling3/></Parent>, depending on the value of the flag.

As it stands now, this would not work, as two or more consecutive tags would not transpile to a single expression.

There are several approaches to that problem:

  1. Wrap the elements into some kind of a parent tag:

    <Parent>{ flag ? <Child/> : <DummyTag><Sibling1/><Sibling2/><Sibling3/></DummyTag>}</Parent>
    

    This is not always acceptable.

  2. Use arrays:

    <Parent>{ flag ? [<Child/>] : [<Sibling1/><Sibling2/><Sibling3/>]}</Parent>
    

    This would make React complain on the elements in the second array having no unique key property, and adding that property would take some extra effort.

  3. Use keyed fragments (facebook/react#2127)

    <Parent>{ flag ? <Child/> : React.createFragment({ sibling1: <Sibling1/>, sibling2: <Sibling2/>, sibling3: <Sibling3/>})}</Parent>
    

    This requires assigning arbitrary keys to the fragments, the syntax is quite cumbersome and it's not JSX.

  4. Use createElement directly, making benefit of ES6 spread syntax:

    React.createElement('parent', {}, ...(flag ? [<Child/>] : [<Sibling1/><Sibling2/><Sibling3/>]))
    

    This is the most straightforward way, as it would be equivalent to either React.createElement('parent', {}, <Child/>) or React.createElement('parent', {}, <Sibling1/>, <Sibling2/>, <Sibling3/>), but it's not JSX either.

My proposal is to make use of the latter solution in JSX, extending JSX with a Spread tag: <...>

This tag could only be used as a non-top element in a JSX tree and could only contain a single JS expression in curly braces, which must evaluate to an array.

This Spread tag <...>{ expression }</...> would transpile to ES6 array spread syntax: ...(expression), so that <Parent><a/><...>{ expression }</...><b/></Parent> becomes React.createElement('parent', {}, React.createElement('a', {}), ...(expression), React.createElement('b', '{}'))

This way, the original problem could be solved by writing:

<Parent/><...>{ flag ? [<Child/>] : [<Sibling1>, <Sibling2>, <Sibling3>]}</...><Parent/>

which would transpile as follows:

React.createElement('parent', {},
    ...(flag ?
        [React.createElement('child', {})] : 
        [React.createElement('sibling1', {}),
         React.createElement('sibling2', {}),
         React.createElement('sibling3', {})]
    )
);

This is almost as simple as the naive solution at the very top, and it produces the exact effect most developers are after: variable number of arguments to createElement with no need to create keys or wrap elements into dummy tags.

Also, it's a pure JSX feature which does not introduce any new React code.

Proposal: <Component { prop: value } /> syntax

A slightly different take on this request.

Allow curly braces without a preceding prop= to define props. This makes it easy to refactor JSX props into objects by removing the need to change prop=value to prop: value, for each prop.

This is currently a syntax error, so allowing this shouldn't break existing code.

Example:

<Component
  {
    bool: true,
    expr: x + y,
    ...spreadObject
  }
/>

It also has nice symmetry with current spread syntax:

const props = {
  bool: true,
  expr: x + y,
  ...spreadObject
}

// This is already valid JSX
<Component
  {
    ...props
  }
/>

Proposal: Allow multiple JSXElement in PrimaryExpression

It will be useful if JSX extends the PrimaryExpression in this way:

  • PrimaryExpression :
    • JSXElements
  • JSXElements :
    • JSXElement JSXElementsopt

That enables us to use multiple JSXElement's on the top level. And transpilers can transpile this to array of elements.

For example in React JSX we gonna be allowed to do:

render() {
  return <span>{ this.renderContent() }</span>
}

renderContent() {
  return (
    <em>1</em>
    <strong>2</strong>
  )
}

Right now we have to do:

renderContent() {
  return [
    <em key="1">1</em>,
    <strong key="2">2</strong>,
  ]
}

Note the commas and keys.

Tool list

It would be a good idea to indicate a list of tools that provide support for JSX until JSX as a format becomes ubiquitous. There is a serious hesitation to adopt JSX out of fear for tooling support. For instance I know there is a fork of JSHint that supports JSX and a beautifier that fully supports JSX, but these tools are not commonly known or easy to search for.

It would also be a good idea to ask users to submit tools, libraries, packages, and other supporting software. Contributions from the community are a great way to determine where the support is and how to better evangelize this format outside of React.

Separate JSX transform from React?

Given recent developments it seems natural to try to separate the JSX transform from React, i.e. to rid ourselves of "React-JSX". The JSX transform could then be adopted independently for use by other frameworks as well, derivative JSX transforms for other JS-based languages could then benefit the JS ecosystem as a whole. Community exploration of alternatives to JSX could become more realistic long-term.

What would it look like? No idea...

var React = require('React');
var createElement = React.createElement;
React.render(<ReactComponent />);
var React = require('React');
React.render(React`<ReactComponent />);

Or perhaps it should just transform into plain objects (owner is a problem)? I have no idea, but unless there are severe practical issues then it seems to me that this is the natural next evolution for JSX (transform).

The only thing that instinctively raises red flags for me is that exploring various optimization strategies might become impossible as that would largely require mutual agreement between the transform and framework I would think. It would probably have to eventually become part of the standard (it could potentially be for the better, but much more friction).

cc @sebmarkbage

Clarify JSX/React WhiteSpace rules

Based on the following test cases:

var p = 0;
// Emit "   "
<div>   </div>;
// Emit "  ", p, "   "
<div>  {p}    </div>;
// Emit only p
<div>  
      {p}    
      </div>;

// Emit only p
<div>
  {p}
    </div>;

// Emit "  3"
<div>  3  
  </div>;

// Emit "  3  "
<div>  3  </div>;

// Emit "3"
<div>   
   3    
   </div>;

// Emit no args
<div>   
   </div>;

// Emit "foo" + ' ' + "bar"
<div>  

   foo

 bar   

  </div>;

// Emit "foo  " + "bar" + "  baz"
<div>foo  <span>bar</span>  baz</div>

// Emit "foo  bar"
<div>foo        bar</div>;

For JSXText (https://facebook.github.io/jsx/) I've drawn the following set of rules:

  1. Trims whitespace in the following cases (mentioned node might be a parent or a sibling):
    • leading whitespace if this is the first node on the same line
    • trailing whitespace if this is the last node on the same line
  2. Inserts a single whitespace if the next sibling is also JSXText and not on the same line
  3. Any whitespace tabs (alt09) is replaced with a single space demo

Am I missing something ... and is this already documented elsewhere (specifically 2 wasn't mentioned explicitly anywhere I could find). Need this information to help with TypeScript/TSX integration 🌹

I know this is specific to React Emit for JSX but this seemed like the more appropriate repo 😃

PS : I've seen http://facebook.github.io/react/blog/2014/02/20/react-v0.9.html#jsx-whitespace

[feature proposal] JSX "Object Literal Property Value Shorthand"

Common problem...

<SomeComponent propVariable={propVariable} />

I repeat "propVariable". I find myself doing this a lot... like, several times for one JSX object (usually a React component) is not uncommon.

Proposed solution...

<SomeComponent [propVariable] />

which would result to the same as the "common problem" example.

EDIT: Dan Abramov suggested this syntax instead:

<SomeComponent {propVariable} />

because "Using square brackets as in computed property name is confusing. In ES6 whatever’s inside brackets is a string name variable" and "[...] would have been more consistent [...]".

Inspired by:

Remove `JSXElement` from `JSXAttributeValue` production?

We just got a bug on TypeScript from someone who was working on some ESLint stuff and found that the TypeScript parser didn't support JSX Elements as Attribute Values. This was news to us because we didn't realize the spec had been changed, and because we had gotten no bug reports from people trying to do this for real.

Babel doesn't support this correctly either:

var x = <foo bar=<qua /> />;

Property value of JSXAttribute expected node to be of a type ["JSXElement","StringLiteral","JSXExpressionContainer"] but instead got "CallExpression"

It'd be trivial for us to implement parsing this, but I'd like to raise this as a potential simplification of the JSX spec given the number of extant consumers.

With no support among the two major JSX transpilers and no user complaints to that end, perhaps this is safe to remove for the sake of simplicity? Adding { } around the attribute value doesn't seem like too much of a burden.

See also #10 / #15

provide `this` context in SFCs when they are invoked via `JSXMemberExpression`

[holy-war question alert!] copied from facebook/react#8714

Would it be possible to provide this context into SFCs when they are invoked via
JSXMemberExpression . JSXIdentifier syntactic form?

My use-case involves unusual ES6 class usage. I'm using them as inheritable containers for SFC's, where individual components could be overridden in descendant classes.

Now I'm forced to autobind all view-methods:

class Base {
    constructor() {
        // would like to avoid these:
        this.Short = this.Short.bind(this);
        this.Full = this.Full.bind(this);
    }
   Short() { return <span>{`${this}`}</span>; }
   Full() { return <div><this.Short /></div>; }
}

class Item extends Base {
    constructor(value) {
        super();
        this.value = value;
    }
    toString() {
        return this.value;
    }
}

var obj = new Item("A");
ReactDOM.render(<obj.Full />, document.getElementById("container"));

A bit more complete example could be found at: https://jsfiddle.net/69z2wepo/67046/

I understand that it is a Holy War question about pure functions and this in JavaScript.
However I'm thinking that this usage of this is legit. Just like a children in props.

It is way too ugly writing:

class Base {
   Short({self}) { return <span>{`${self}`}</span>; }
   Full({self}) { return <div><self.Short self={self} /></div>; }
}

class Item extends Base {
    constructor(value) {
        super();
        this.value = value;
    }
    toString() {
        return this.value;
    }
}

var obj = new Item("A");
ReactDOM.render(<obj.Full self={obj} />, document.getElementById("container"));

Isn't it?


I even would be happy if

<a.b.c />

would be treated as

<a.b.c self={a.b} />

just like children - provide some special member in props. However it could be problematic as it will clash with existing user code.

Theoretical: Drop JSXText

Bear with me here :)
JSX currently looks like this:

<div>
  {'Name of things:' + name} -- no one really does this
  Number of things: {count}
  <span>
    Some {cond ? children : null}
    {'Some newline\n'}
  </span>
</div>

What if it looked like:

<div>
  'Name of things: ' + name, -- it's now intuitive to concatenate
  'Number of things: ', count
  <span>
    'Some ', (cond ? children : null),
    'Some newline\n'
  </span>
</div>
  1. "Arbitrary" JSX white-space rules can be chucked out the window, it's JS-strings plain and simple.
  2. It's super easy to add and see explicit leading/tailing white-space, no weird encoded values or lazy hacks.
  3. It's super easy/intuitive to concatenate stringy content instead of lazily creating more children.
  4. It's JS through-and-through + JSX-elements, comments behave as you would expect.

I imagine that it would be possible to omit ,, if you would really want to.

I realize this would be a ginormous departure from the heavily HTML-based syntax we have currently. From a purely theoretical/technical perspective it makes perfect sense in my opinion, but the practical aspects are obviously very questionable. I don't expect anyone to embrace this, but I think it's an interesting thought.

JSX "requires" special token parsing, should be documented?

I haven't read it in detail yet (so forgive me if I missed it), but we may need to add some additional documentation detailing the need for a separate token table when parsing JSX (see facebookarchive/esprima#39).

There are two options here as I see it:

  1. Disable conflicting JS tokens when parsing JSX.
  2. Use an entirely separate token table for JSX (just a handful).

The upside of 1 is that misplaced tokens emit familiar errors and the implementation is simpler, but also a bit more fragile. With option 1 <Comp == would yield an error for == instead of just =.

How can we insert elements dynamically

For example:

props.providedElement
? <div className="a">
      <span>aaaa</span>

      {props.providedElement}
  </div>
: <div className="a">
    <span>aaaa</span>

    <button>bbbb</button>

    <input className="ccc" />
  </div>

At now,the <div className="a"><span>aaaa</span></div> part is repetitive,but I can't write something like:

<div className="a">
    <span>aaaa</span>

    {props.providedElement || 
       <button>bbbb</button>

       <input className="ccc" />    
    }
</div>

This will cause syntax error,but we can't wrap the element like:

<div className="a">
    <span>aaaa</span>

    {props.providedElement || 
       <div>
           <button>bbbb</button>

           <input className="ccc" />    
       </div>
    }
</div>

because it will break the construction of html,maybe we need to do some extra work to fix it or it just can't be fixed.

Maybe we can do this:

<div className="a">
    <span>aaaa</span>

    {props.providedElement || 
        [<button>bbbb</button>, 
         <input className="ccc" />
        ]
    }
</div>

But it is a little difficult to read and maintenance.So,I want to ask is there any good way to solve this?

SpreadChildren

I would like to propose this syntax:

const items = [
  <li />,
  <li />,
  // ...
];

<ul>
  <li />
  { ...items }
  <li />
</ul>

For React this would transform into this:

// Simplified version
React.createElement('ul', null, <li />, ...items, <li />);

Why? Because some times in conditions it's needed to use an array with statically (never changing) defined JSX items. I think it's reasonable since workaround was proposed but just without JSX syntax: facebook/react#2816 (comment)

[Feature Request]: Provision for style/external styles

In JSX we can only apply styles in JSON object. There is some provision required, So user can also apply classes with attribute selector and other selectors
static style() { <style> [#/./name][attribute="value"][ |: pseudo| :: pseudo] { border: 1px solid #efefef; } </style> }

Is JSXNamespacedName needed?

Maybe it's just me, but it doesn't look clear why do we have JSXNamespacedName in spec, if, as far as I remember, after long discussions JSXMemberExpression was introduced exactly as replacement for first one (it's not supported by E4X but looks more familiar as for JS).

Or was it just for React (which emits error on trying to use namespaced name) and :-based namespaces were preserved for DOM-based JSX implementations?

It's somewhat confusing, so if there's reason for both to exist, maybe it makes sense to add a description cases in which one or another namespace syntax should be used. If there's no such reason, then maybe it makes sense to remove it from spec as deprecated so new tools wouldn't have to handle it.

Proposal: implicitly use do-expression for any JSX expr container

I just saw this tweet: https://twitter.com/vslinko/status/619581969903550464

And wondering if there are any downsides or backward incompatibilities to enabling do-expression over any JSX expression container so that if and other statements could be used directly inside of braces? My understanding is that for regular expression do { ... } will preserve compatibility and thus wrapping will just enhance contents to support statements as well.

@vslinko @sebmarkbage @jeffmo @wycats @sebmck

Non-quoted multi-line JS string literal parsing instead of JSX text

I propose the following:
Trim leading spaces and tabs after newlines (indentation) and then apply regular string literal parsing (but over multiple lines and without quotes). It may be advisable to trim tailing spaces and tabs too to avoid source code incompatibilities with editors auto-trimming on save.

There are lots of benefits to this:

  1. (X)HTML-entities are now a thing of the past. JSX attribute strings (HTML) and JSX expression container strings (JS) are now parsed the same way.
  2. You can write complex strings without breaking texts up into separate children (foo{'}'}bar) or having to resort to using unintuitive HTML-entities (foo&#125;bar), just escape with \.
  3. We can intuitively and easily control whitespace by simply escaping \<space> (\<eol> gives you a space too).
  4. A single-line JSX text behaves identically to its counter-part JS string literal.

The two practical issues I see are:

  1. &nbsp; is common and \xA0 is not an overly obvious escape code. This applies if you're dealing with JS anyway, but most are probably only used to typing it as a HTML-entity inside JSX. It's a trade-off (perhaps editors will catch-up and actually render a hint for literal nbsp chars with a little persuasion too).
  2. It makes the most technical sense to drop the current implicit space between newlines (and I'm all for it) but it could make it seem a bit alien to some users, implicit space can be kept and will then have to be omitted if the char before the newline is a white-space char.
<>  foo  </>
=> '  foo  '
<>
  foo
</>
=> 'foo'
<>
\  foo \
</>
=> '  foo  '
<>
\ \ foo\ \
</>
=> '  foo  '
<>
  foo
  bar
</>
=> 'foobar'
<>
  foo\
  bar
</>
=> 'foo bar'
<>
  foo\nbar
</>
=> 'foo\nbar'
<>
  foo\n
  bar
</>
=> 'foo\nbar' (actual newline)
<>
  foo\<\{
  bar
</>
=> 'foo<{bar'

What's not to like?
PS. It should be noted that this is easily non-destructively codemod:able too.

cc @sebmarkbage @jeffmo @zpao @spicyj

Using `this` in the element name.

It'd be nice to use JavaScript everywhere, f.e.:

    constructor(props) {
        super(props)

        this.mapContainerElement = React.createClass(
            render() {
                return (
                    <Node ref="mapNode" position={[0,0,0]}>
                    </Node>
                )
            },
        )
        this.bigGpsButtonElement = React.createClass(
            render() {
                return (
                    <Button ref="bigGpsButton">
                    </Button>
                )
            },
        )
    }

    /**
     * Renders the default mapContainerElement and bigGpsButtonElement.
     */
    render() {
        return (
            <Node _famousParent={this}>
                <this.mapContainerElement ref="mapContainerElement" />
                <this.bigGpsButtonElement ref="bigGpsButtonElement" />
            </Node>
        )
    }

Note the use of this in the render function. That makes sense. If we can put a normal variable reference there, we should likewise be able to use an object reference.

JSXMemberExpression should allow comments?

The documented JSXMemberExpression does not allow comments, it's allowed in JS so it makes sense for JSX to support it too (although we might not want to allow whitespace?). But it's obviously not important at all.

Object literal syntax for attributes

Since you already support:

var x = { a: 3, b: 'foo' };
var y = <MyClass { ...x } />;

And the current operation in JS for spread syntax are:

var attributes = { attr1: 1, attr2: 2, ... } => {...attributes}

Notice the placeholder punctuations { } remains the same.

I just have to ask why you don't support:

var y = <MyClass { attr1: 1, attr2: 2 } />;

It's less foreign syntax for JS. Also the placeholder punctuations remains the same. It is also a more productive syntax then having to write multiple { } for each attribute.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.