markdown-to-jsx icon indicating copy to clipboard operation
markdown-to-jsx copied to clipboard

I there a way to make img tags render as top level elements

Open kedarguy opened this issue 7 years ago • 7 comments

currently even if the markdown file has just an img, it will render as so: <p><img/></p>

Is there a way to make img's top level block components?

so I would get from a markdown file with a couple of pargraph's and an img in the middle the following html:

<p>some text/markdown</p>
<p>some text</p>
<img/>
<p>some text</p>

kedarguy avatar Aug 31 '18 10:08 kedarguy

I played with this originally but most people didn't seem to like how it worked and I got some issues around it.

quantizor avatar Aug 31 '18 16:08 quantizor

I have a similar issue, only I'm using the overrides to replace the img prop with a React component (Gatsby Image) and that's creating invalid markup (p > div). For now I'm sidestepping the issue with this approach/hack:

<MarkdownBlock
  overrides={{
    img: MyImageComponent
    p: props => {
      return props.children.some(child => typeof child === "string") ? (
        <p {...props} />
      ) : (
        <div {...props} />
      )
    },
  }}
>
  {content}
</MarkdownBlock>

Effectively I'm checking the type of the children (bad since React expects children to be treated as opaque) and if it's not a string render a div element. This has been working for the project I need it on, but I suspect there are more than a few pitfalls I haven't run into yet.

It would be great to get this as an option, or for the library to expose a function to an overridden element that would let it determine the type of the parent/ancestor.

coreyward avatar Jul 04 '19 16:07 coreyward

@probablyup I see you are looking for maintainers... so my hopes aren’t high. Any chance a more elegant fix has been developed? I am also looking for a way to not have img tags nested in a p tag. The current nesting makes it hard to develop more elaborate overrides such as wrapping images in Zoom.

FYI, I submitted a pull request to DefinitelyTyped to allow these kinds of overrides.

interface ImageProps {
  alt: string
  src: string
}

const Image: FunctionComponent<ImageProps> = function(props) {
  return (
    //@ts-ignore
    <Zoom>
      <img alt={props.alt} src={props.src} width="100%" />
    </Zoom>
  )
}
Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.

sunknudsen avatar Feb 26 '20 16:02 sunknudsen

The following hack works (inspired by @coreyward’s approach).

It removes nesting altogether when a p tag has an Image child.

p: {
  component: props => {
    for (let child of props.children) {
      console.log(child)
    }
    return props.children.some(
      (child: JSX.Element) => child.type && child.type === Image
    ) ? (
      <Fragment>{props.children}</Fragment>
    ) : (
      <p {...props} />
    )
  },
},

sunknudsen avatar Feb 26 '20 19:02 sunknudsen

Just ran into this issue myself. I am using Typescript and am having trouble utilizing the hacks @coreyward and @sunknudsen posted, specifically with:

props.children.some(child => typeof child === "string")

What is the some method on children? I cannot find any reference to some in React. Not sure what type children is here as it's currently typed as any.

cronin4392 avatar Sep 30 '20 12:09 cronin4392

You'd want to use React.Children.toArray(props.children).some

https://reactjs.org/docs/react-api.html

quantizor avatar Sep 30 '20 12:09 quantizor

So I also run into this issue. The same case as @coreyward. I implement Gatsby images and getting my custom override component wrapped into p tag and so invalid html5.

The main problem is why for god's sake you're getting wrapped override component?

vavra7 avatar Jul 30 '21 13:07 vavra7