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

Code is wrapped in an exrea <pre> even with a custom component #820

Closed
4 tasks done
angrybacon opened this issue Mar 2, 2024 · 9 comments
Closed
4 tasks done

Code is wrapped in an exrea <pre> even with a custom component #820

angrybacon opened this issue Mar 2, 2024 · 9 comments
Labels
🙋 no/question This does not need any changes 👎 phase/no Post cannot or will not be acted on

Comments

@angrybacon
Copy link

angrybacon commented Mar 2, 2024

Initial checklist

Affected packages and versions

react-markdown@9.0.1

Link to runnable example

https://codesandbox.io/p/sandbox/react-markdown-820-m63fxn

Steps to reproduce

const markdown = `Before
~~~
Code
~~~
After`;

<Markdown components={{ code: (props) => <pre {...props} /> }}>
  {markdown}
</Markdown>
<p>Before</p>
<pre>
  <pre>Code</pre>
</pre>
<p>After</p>

Expected behavior

A custom component for code blocks should replace the default pre wrapper.

Actual behavior

My code block is wrapped in 2 pre elements. This is relevant for cases like https://github.com/remarkjs/react-markdown?tab=readme-ov-file#use-custom-components-syntax-highlight where the horizontal scroll from react-syntax-highlighter is broken as a result.

Runtime

No response

Package manager

No response

OS

No response

Build and bundle tools

No response

@github-actions github-actions bot added 👋 phase/new Post is being triaged automatically 🤞 phase/open Post is being triaged manually and removed 👋 phase/new Post is being triaged automatically labels Mar 2, 2024
@ChristianMurphy
Copy link
Member

ChristianMurphy commented Mar 2, 2024

Welcome @angrybacon! 👋
Sorry you ran into some confusion, the components prop is working as expected.

components allow you to wrap the HTML markdown generates with custom elements.
For a codeblock markdown generates a <pre> tag with a <code> tag inside.
If you map the code tag to pre, then you do indeed get two <pre> tags.

It's a bit hard to help because it's unclear what your end goal is.
If you want syntax highlighting, try the example you linked https://github.com/remarkjs/react-markdown?tab=readme-ov-file#use-custom-components-syntax-highlight

If you're looking for something else, please explain.

@ChristianMurphy ChristianMurphy closed this as not planned Won't fix, can't repro, duplicate, stale Mar 2, 2024

This comment has been minimized.

@ChristianMurphy ChristianMurphy added the 🙋 no/question This does not need any changes label Mar 2, 2024
@github-actions github-actions bot added 👎 phase/no Post cannot or will not be acted on and removed 🤞 phase/open Post is being triaged manually labels Mar 2, 2024
@angrybacon
Copy link
Author

This is relevant for cases like https://github.com/remarkjs/react-markdown?tab=readme-ov-file#use-custom-components-syntax-highlight where the horizontal scroll from react-syntax-highlighter is broken as a result.

I am already using this and their inline styles are applied to the pre that they generate themselves, including the overflow property. The extra pre wrapper breaks the horizontal scroll. My current workaround is to force unwrapping pres specifically but I'd rather not have to do it.

<Markdown
  ...
  disallowedElements={['pre']}
  unwrapDisallowed
/>

@angrybacon
Copy link
Author

Does that mean that I should instead customize the pre component, extract the code's children and use Prism with that?

@ChristianMurphy
Copy link
Member

I am already using this and their inline styles are applied to the pre that they generate themselves, including the overflow property.

Okay, you aren't in the example you shared, but I think I follow.

My current workaround is to force unwrapping pres specifically

If you only want one level, one way or another you will need to unwrap.
you could do that in a rehype plugin, you could do that with disallows, or you could set the renderer for <pre> to a Fragment.
From the limited information I have (this is still an XY problem https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)
I'd recommend setting the component for <pre> something like pre: ({children}) => (<>{children}</>)

Does that mean that I should instead customize the pre component, extract the code's children and use Prism with that?

You could do that too.

@angrybacon
Copy link
Author

I only meant to provide the most minimal context but after a good night's sleep I now see where my confusion comes from: within Markdown I can have inline code markup and code blocks. The former is content wrapped in code, inline. While the latter would be a block element wrapped with pre that contains itself a code wrapper around the actual content.

Since I'm customizing the code component from react-markdown to handle both blocks and inline code markup your suggestion of rendering <pre> with a fragment does make sense thanks for the suggestion.

@hexcowboy
Copy link

While I do follow, the way react-markdown handles both of these does not seem correct. Why not just use <code> for inline code and <pre> for code blocks?

The issue here is that you aren't able to customize both inline code and code blocks separately, since react-markdown places codeblocks in <pre><code>...</code></pre>. If you render <pre> as a Fragment, then your codeblocks are forced to use the same styles/props as inline code.

@ChristianMurphy
Copy link
Member

micromark, remark, and react-markdown follow the CommonMark standard https://spec.commonmark.org/0.31.2/
We are not going to break with the standard.

You are welcome to use plugins to customize the output to your liking. https://unifiedjs.com/learn/

@angrybacon
Copy link
Author

angrybacon commented May 13, 2024

Why not just use <code> for inline code and <pre> for code blocks?

Because that wouldn't be semantically correct. The <code> element doesn't imply formatting but <pre> does.

FWIW here is how I differentiate the 2 in my code:

import { type Components } from 'react-markdown';

const Code: Components['code'] = ({ children, className = '', node }) => {
  if (!node?.position || !children) {
    console.error('Could not parse code node', node);
    return <>{children}</>;
  }
  if (node.position.start.line === node.position.end.line) {
    return <CodeInline>{children}</CodeInline>;
  }
  // NOTE Languages are passed down through the class name with `react-markdown`
  const [, language] = className.split('-');
  return <CodeBlock language={language || 'text'}>{children}</CodeBlock>;
};

Edit: I notice while posting this that GitHub doesn't use <code> for code blocks. I don't know whether <code> is just preferred or mandatory for accessibility topics though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🙋 no/question This does not need any changes 👎 phase/no Post cannot or will not be acted on
Development

No branches or pull requests

3 participants