facebook / jsx

The JSX specification is a XML-like syntax extension to ECMAScript.
http://facebook.github.io/jsx/
1.96k stars 133 forks source link

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

Open Danilo-Araujo-Silva opened 7 years ago

Danilo-Araujo-Silva commented 7 years ago

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)?

syranide commented 7 years ago

Unless it has been changed (don't think so), then you should use dangerouslySetInnerHTML with style for React, not provide a string child.

But to the point, with ES6 the solution to this is simple, use template strings:

<style>{`
  foo bar ${foobar} { .. }
`}</style>
var html = {_html: `
  foo bar ${foobar} { .. }
`};
<style dangerouslySetInnerHTML={html} />
sebmarkbage commented 7 years ago

The template literal solution indeed solve this. If we go down the route of https://github.com/facebook/jsx/issues/35 then the template literal solution might seem more natural to go for.

Although I might also suggest that we should support an object as the child of style in React which has all the selectors as properties. That is already how the style attribute works in React. It simply uses the existing syntax for data structures that already exist in JS.

<style>{{
  '*': {
    'background-color': 'red'
  }
}}</style>

This allows you to specify structured data that could even be type specific using CSSOM instead of having to parse a string.

giuseppeg commented 7 years ago

Ideally it would be great if style's content could be parsed as TemplateLiteral when it is just text and doesn't start with {:

<style>
  div { color: red; }
  span { background: ${ color } }
</style>

// parsed like

<style>{`
  div { color: red; }
  span { background: ${ color } }
`}</style>

For styled-jsx this would be amazing.

Buslowicz commented 6 years ago

Sorry for digging this up, but are there any plans to implement something to solve this? Custom delimiters would be great, or at least a way to specify which tags content should not be parsed.