Open karlhorky opened 4 days ago
Heyyyyy!
This is intentional, because it isn’t needed, you can do:
Video: () => <div>video replacement</div>
And then:
<Video />
Why is this one character change, which is inspired by how JSX itself works (if you write <video>
it’s plain, if you write <Video>
it’s a reference), not viable for you?
Video
insteadThe following keys can be passed in components:
HTML equivalents for the things you write with markdown such as h1 for
# heading
(see § Table of > components for examples) wrapper, which defines the layout (but a local layout takes precedence)
- anything else that is a valid JavaScript identifier (foo, Quote, _, $x, a1) for the things you write with JSX (like
<So />
or<like.so />
, note that locally defined components take precedence
components
prop), both can change the HTMLis it preferred to use the word "replaces" or "overrides" like the community has been using? or something more like "renders" with a longer description?
it depends; importantly, MDX is not coupled to React. JSX runtimes could accept whatever. Functions, classes, symbols, whatever. It’s also not coupled to HTML semantics. You could do emails or rss feeds or ANSI rendering; so, whether you’re replacing/overriding/rendering/swapping/etc seems related to what else you’re doing
what is the preferred terminology for describing the plural things that are being passed as the keys of the object passed to the components prop?
names, keys, identifiers, fields? Keep in mind that JSX allows objects too; <very.deeply.nested />
, so very
here is also a key in components
I haven't yet collected all of the reasons why others have said they wanted this, but I'll list some reasons why overriding <video>
or other HTML literal tags may be desirable off the top of my head:
I can understand if there are technical reasons why MDX does not want to support these use cases - are there technical reasons for this? The original workaround suggested a plugin that no longer works. So if there's a technical reason for it not working or a new version of the workaround for changes in MDX, that would be interesting.
Regardless of whether there is a new workaround or not, I do think the whole flow should be more explicitly documented, with a few examples of what HTML tags are not replaced.
Here is a detailed list of suggestions, based on my original list above and your questions above, but reordered to match the order of the page:
4) A text description of what MDX does with "an object mapping component names to components", using preferred terminology
-There is one special prop: `components`. It takes an object mapping component names to components. Take this example:
+There is one special prop: `components`. Pass an object containing either / both of:
+
+1. Component name keys to components values eg. `Video: () => { ... }`
+2. HTML element names to components eg. `img: Image`
+
+MDX will use this object to replace any occurrences in your MDX file with the component passed as the value.
+
+Take this example:
This may have issues which require further clarification eg. that these key/value pairs above only apply to MDX with HTML.
example.mdx
and example.jsx
3) A short code example showing what the
components
prop does (not onlyexample.mdx
andexample.jsx
, but also the resulting HTML)
Take this example:
```mdx path="example.mdx"
# Hello *<Planet />*
It can be imported from JavaScript and passed components like so:
// @filename: types.d.ts
import type {} from 'mdx'
// @filename: example.jsx
/// <reference lib="dom" />
/* @jsxImportSource react */
// ---cut---
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(
<Example
components={{
Planet() {
return <span style={{color: 'tomato'}}>Pluto</span>
}
}}
/>
)
+This results in the following HTML:
+
+html +<h1>Hello <span style="color: tomato">Pluto</span></h1> +
Again, my example above may likely be missing something or needs tweaks to be 100% accurate for the wide use cases of MDX - it's intended as an illustration of what I mean, and something that would be a very helpful missing piece to showcase what `components` does.
## 2) [Using MDX -> Components section](https://mdxjs.com/docs/using-mdx/#components) - Explicit description that HTML literal elements not replaced
> 2) An explicit description of this intended behavior - that MDX will by default not override or replace any HTML literal elements (maybe with a link to [the original issue](https://github.com/mdx-js/mdx/issues/821) as background?)
![Screenshot 2024-07-07 at 19 01 00](https://github.com/mdx-js/mdx/assets/1935696/d86840e4-f7fd-4114-a728-678ada62585f)
```diff
-The following keys can be passed in `components`:
+The following keys can be passed in a `components` object:
-* HTML equivalents for the things you write with markdown such as `h1` for
- `# heading` (see [§ Table of components][toc] for examples)
+* Markdown syntax-generated HTML elements eg. if you write `# heading` in your MDX file,
+ the key is `h1` (this does not include all HTML, see [§ Table of components][toc] for examples)
* `wrapper`, which defines the layout (but a local layout takes precedence)
-* `*` anything else that is a valid JavaScript identifier (`foo`,
+* anything else that is a valid JavaScript identifier (`foo`,
`Quote`, `_`, `$x`, `a1`) for the things you write with JSX (like
`<So />` or `<like.so />`, note that locally defined components take
precedence)**‡**
+
+Caveat: the following keys in a `component` object will not be replaced:
+
+* HTML elements which do not use Markdown syntax eg. `<img>`, `<video>`, etc. in `.mdx` files
+ ([see background](https://github.com/mdx-js/mdx/issues/821)) - for these use cases, use a custom component like `Video: () => { ... }`
**‡** If you ever wondered what the rules are for whether a name in JSX (so `x`
in `<x>`) is a literal tag name (like `h1`) or not (like `Component`), they are
as follows:
A few first suggestions above.
Considering it more, I think that the potential confusion of HTML literal elements not being replaced would actually warrant another section showing:
.mdx
file.jsx
file (with components
prop, some of which are invalid eg. video
)To be a companion for the text to be 100% explicit that some components (such as literal HTML elements in the .mdx
file) will not be replaced, and will have the original elements as in the .mdx
file.
- Why are the existing docs not clear? Emphasis to show what I mean
As in my diff above:
HTML
, which is misleading and makes the rest of the words in that first bullet aim to try to explain that they are related to Markdown syntaxcomponents
object keys<video>
*
in the last bullet looks like a literal value that can be used (eg. like the *
selector in CSS). I'm assuming that this is not the case, so I reworded for clarity
- Isn’t that the example at “Here are some other examples of passing components”? It has text explaining each thing in the comments?
I think your comment was mostly referring to my 2) suggestion. It doesn't relate to 3) because 3 is about having an HTML result example directly next to the other example.mdx
and example.jsx
code blocks.
Including the screenshot of the example code block here for reference:
I like this example code block, yes! I don't think that it describes in detail which things can and cannot be used (which I'm proposing in 2), and the comments are pretty easy to miss. But I love these types of examples, and I think it's very valuable.
example.mdx
and example.jsx
3i) A short code example showing that the resulting HTML does not change with usage of the MDX provider
Same idea as above with 3) - a separate HTML "result" code block. Showing that the resulting HTML is the same, to make the mental models concrete that the docs reader is building up and confirm their assumptions.
Thanks for sharing @karlhorky!
This comes up often enough I'd be okay with there being some documentation. Similar to @wooorm I view overriding plain HTML as a really bad idea. So if it were included it may make sense to do something like Micromark extensions https://github.com/micromark/micromark?tab=readme-ov-file#extending-markdown
With a sizable section on alternatives and why you may not want to do this (most people), before offering a path to the persistent who have a super specific use case.
Initial checklist
Affected packages and versions
@mdx-js/react@3.0.1, next@14.2.4, react@^18
Link to runnable example
No response
Steps to reproduce
app-dir-mdx
example from Remcoexperimental.mdxRs
fromnext.config.js
video: () => <div>video replacement</div>
inmdx-components.tsx
<video />
inapp/message.mdx
<video />
appearing in HTML in DevTools, instead of the<div>
rehypePlugin
suggested by @wooorm)<video />
still appearing in HTML in DevTools, instead of the<div>
Or, to skip steps 1-6, a reproduction repo:
This has occurred because some users have seen the "overriding literal HTML in MDX" as unexpected behavior (as in @adamwathan's original https://github.com/mdx-js/mdx/issues/821). Other users (including myself) have found it unexpected that these HTML elements are not being overridden, especially in the case of HTML elements which have no Markdown syntax equivalent, such as
<video>
, where it would be amazing to be able to userehype-mdx-import-media
with<video>
out of the box without any additional plugins:Expected behavior
The Using MDX page (specifically the Components section and the MDX provider section) should include:
components
prop does (not onlyexample.mdx
andexample.jsx
, but also the resulting HTML)components
prop?Actual behavior
The Using MDX page (specifically the Components section and the MDX provider section) includes:
<video>
, writing an additional remark plugin for support of![]()
syntax can work)example.mdx
andexample.jsx
, not including the resulting HTMLexample.mdx
andexample.jsx
resulting HTML does not change with usage of the MDX providerRuntime
Node v20
Package manager
No response
OS
macOS
Build and bundle tools
Next.js