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

Can't access props with inline JSX #556

Closed
johno opened this issue Apr 26, 2019 · 7 comments · Fixed by #1039
Closed

Can't access props with inline JSX #556

johno opened this issue Apr 26, 2019 · 7 comments · Fixed by #1039
Labels
🐛 type/bug This is a problem

Comments

@johno
Copy link
Member

johno commented Apr 26, 2019

With the new inline parsing of JSX blocks we no longer allow props access like we did in v0:

This is some inline JSX: <span>{props.foo}</span>

We now result in the following AST:

{
  "type": "root",
  "children": [
    {
      "type": "paragraph",
      "children": [
        {
          "type": "text",
          "value": "This is some inline JSX: "
        },
        {
          "type": "jsx",
          "value": "<span>"
        }
        {
          "type": "text",
          "value": "{props.foo}",
        },
        {
          "type": "jsx",
          "value": "</span>"
        }
      }
    }
  ]
}

This is problematic because "{props.foo}" will be escaped and end up like:

<span>{`{props.foo}`}</span>

Potential solution

Rather than parsing open/close blocks separately we should probably return a single node:

{
  type: 'jsx',
  value: '<span>{props.foo}</span>`
}

However, this can be problematic if folks are using Markdown inside inline JSX because their embedded Markdown will suddenly no longer work. This is also why remark parses inline HTML in that way. In the context of MDX, though, I'm not sure this is correct and we want it as a single JSX node.

cc/ @ChristopherBiscardi @wooorm @timneutkens @jxnblk @jlengstorf


AST Explorer example

@johno johno added the 🐛 type/bug This is a problem label Apr 26, 2019
@wooorm
Copy link
Member

wooorm commented Apr 29, 2019

Yeah I can see how people would expect markdown to work inside inline JSX.

Alternatively, could we look at and detect the braces?

@johno
Copy link
Member Author

johno commented Apr 29, 2019

Alternatively, could we look at and detect the braces?

Yeah, this is prolly the most reasonable approach. Then we could avoid string escaping those braces so something like:

<span>Hi, {props.foo}</span>

Would become:

<span>{`Hi, `}{props.foo}</span>

@johno
Copy link
Member Author

johno commented Apr 29, 2019

After some more thinking on this we might need to change the AST structure for inline JSX a bit. So each inline JSX tag has children so that we can parse the Markdown and nest inline JSX tags in a way that is unambiguous:

{
  "type": "root",
  "children": [
    {
      "type": "paragraph",
      "children": [
        {
          "type": "text",
          "value": "This is some inline JSX: "
        },
        {
          "type": "jsx",
          "children": [
            {
              "type": "jsx",
              "value": "<span>"
            },
            {
              "type": "emphasis",
              "children": [
                {
                  "type": "text",
                  "value": "Hi"
                }
              ]
            },
            {
              "type": "jsx",
              "value": "{props.foo}"
            },
            {
              "type": "jsx",
              "value": "</span>",
            }
          ]
        }
      ]
    }
  ]
}

@polarathene
Copy link

polarathene commented May 21, 2019

I think I've run into this issue, but rather than pass any props with braces I just wanted to wrap markdown content within a JSX element.

At first this wasn't an issue, the content I was wrapping was plain text for the first line, then further paragraphs that used markdown syntax rendered correctly. I had an inline JSX element where the markdown just seemed to return as a string instead of being properly converted..

import InstallPath from './embeds/install-path.mdx'

In the Rust development environment, all tools are installed to the <InstallPath/> directory,
import PlatformSpecific from '../../components/detect-platform'

<PlatformSpecific unix>`/.cargo/bin`</PlatformSpecific>
<PlatformSpecific win>`%USERPROFILE%\.cargo\bin`</PlatformSpecific>

Which would output:

In the Rust development environment, all tools are installed to the `/.cargo/bin` directory,

Instead of:

In the Rust development environment, all tools are installed to the /.cargo/bin directory,

Turned out the content would not render as markdown until after the first blank line:

<PlatformSpecific unix>

`/.cargo/bin`
</PlatformSpecific>

Which works, but forces a new line in the actual content too breaking that sentence. Removing the blank line above it renders all as a string like when I originally had it all on a single line. Any content before that first blank line can be plain text or JS/JSX I take it.

Is that the intended behaviour?

The suggested brace approach works I guess, would that allow for such, as using a variable that gets replaced in code fences?(or my example if I passed a prop in with a string to be rendered as an InlineCode element, rather than creating a component specifically for it)

Note a blank line isn't required afaik if you start with heading content #

@polarathene
Copy link

The content being treated as a newline/block was due to implicitly generated <p> tag wrapping the MDX content by default. AFAIK, I just have to opt-out of that by changing the wrapper to a fragment if possible. Sometimes it would be desirable at least when importing MDX files to also have the implicit paragraph tag wrapping the content, is there a way to opt-in/out?

@larrybotha
Copy link

larrybotha commented Jun 27, 2019

For anyone else struggling with this, one workaround is to wrap the line of text in React.Fragment or span:

<React.Fragment>This is some inline JSX: {props.foo}</React.Fragment>

Note: Markdown needs to be used outside of JSX, otherwise the content isn't parsed by MDX

e.g.

<React.Fragment> > This is some inline JSX: {props.foo}</React.Fragment>

results in

> This is some inline JSX: [foo value]

instead of

<blockquote>
  This is some inline JSX: [foo value]
</blockquote>

@johno
Copy link
Member Author

johno commented Jul 16, 2020

I'm going to go ahead and close this since it will be addressed in MDX v2 (and likely won't update the v1 parser any more) thanks to @wooorm's hard work. If you want to get up and running with it now you can yarn add @mdx-js/mdx@next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 type/bug This is a problem
Development

Successfully merging a pull request may close this issue.

4 participants