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

Docs: Missing explicit docs and workaround for overriding literal HTML elements in MDX #2503

Closed
4 tasks done
karlhorky opened this issue Jul 3, 2024 · 14 comments
Closed
4 tasks done
Labels
💪 phase/solved Post is done

Comments

@karlhorky
Copy link
Contributor

karlhorky commented Jul 3, 2024

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

  1. Set up the Next.js App Router + MDX app-dir-mdx example from Remco
  2. Remove experimental.mdxRs from next.config.js
  3. Add a line video: () => <div>video replacement</div> in mdx-components.tsx
  4. Add a line <video /> in app/message.mdx
  5. Observe <video /> appearing in HTML in DevTools, instead of the <div>
  6. Research and find the following information in docs and GitHub issues / PRs
    1. Don't replace literal HTML elements with MDXProvider #821
    2. components do not override the built-in react components kentcdodds/mdx-bundler#160
    3. Override jsx built-in components #2050
    4. Workaround: Add Option to override built-in HTML elements #2052 (comment)
    5. Workaround: components do not override the built-in react components kentcdodds/mdx-bundler#160 (comment)
    6. visit() video elements of type mdxJsxFlowElement? remcohaszing/rehype-mdx-import-media#2 (comment)
  7. Attempt the workaround from 5iv. and 5v. (adding the rehypePlugin suggested by @wooorm)
  8. Observe <video /> still appearing in HTML in DevTools, instead of the <div>

Screenshot 2024-07-03 at 13 38 04

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 #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 use rehype-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:

  1. A new working workaround (documented as an officially-blessed configuration) for overriding / replacing HTML literal elements in MDX
  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 as background?)
  3. A short code example showing what the components prop does (not only example.mdx and example.jsx, but also the resulting HTML)
    1. A short code example showing that the resulting HTML does not change with usage of the MDX provider
  4. A text description of what MDX does with "an object mapping component names to components", using preferred terminology:
    1. Verb "replaces" / "overrides" / alternative: is it preferred to use the word "replaces" or "overrides" like the community has been using? or something more like "renders" with a longer description?
    2. Plural noun "custom components" / "MDXComponents" / "MDX components" alternatives: 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?

Actual behavior

The Using MDX page (specifically the Components section and the MDX provider section) includes:

  1. No current working workaround (although for <video>, writing an additional remark plugin for support of ![]() syntax can work)
  2. No explicit description that certain literal HTML elements will not be overridden
  3. Code example of only example.mdx and example.jsx, not including the resulting HTML
    1. A diff of example.mdx and example.jsx resulting HTML does not change with usage of the MDX provider
  4. No text description of what MDX does with "an object mapping component names to components", using preferred terminology

Runtime

Node v20

Package manager

No response

OS

macOS

Build and bundle tools

Next.js

@wooorm
Copy link
Member

wooorm commented Jul 3, 2024

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?

  • 1. The “workarounds” are not recommended, it is recommended to write Video instead

  • 2. Why are the existing docs not clear? Emphasis to show what I mean

    The 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
  • 3. What do you have in mind? There are many examples on the website already, such as https://mdxjs.com/docs/using-mdx/, https://mdxjs.com/table-of-components/, the readmes? I do think that the playground solves this already; people can try any MDX and see the result?

  • 3.i. Providers are a runtime thing to inject more things (just like the components prop), both can change the HTML

  • Isn’t that the example at “Here are some other examples of passing components”? It has text explaining each thing in the comments?

  • is 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

@karlhorky
Copy link
Contributor Author

karlhorky commented Jul 7, 2024

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:

  1. copying and pasting HTML
  2. tooling integrations for HTML elements eg. linting for attributes which should be there
  3. greppability in codebase
  4. style preference towards usage of HTML elements instead of Markdown elements / JSX elements

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) Using MDX -> Components section - text description of what MDX does

  1. A text description of what MDX does with "an object mapping component names to components", using preferred terminology

Screenshot 2024-07-07 at 18 32 15

-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.

3) Using MDX -> Components section - Resulting HTML of example.mdx and example.jsx

  1. A short code example showing what the components prop does (not only example.mdx and example.jsx, but also the resulting HTML)

Screenshot 2024-07-07 at 18 48 42

Take this example:

```mdx path="example.mdx"
# Hello *<Planet />*
```

It can be imported from JavaScript and passed components like so:

```jsx twoslash path="example.jsx"
// @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 - Explicit description that HTML literal elements not replaced

  1. 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 as background?)

Screenshot 2024-07-07 at 19 01 00

-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)
  • HTML result

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:

  • the first bullet point starts with 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 syntax
  • there is no mention of any exceptions to HTML, except for the link that goes to a different page
  • there is no mention of what users cannot use in the components object keys
  • there is no suggestion of what users do if they run into the limitation of <video>
  • unrelated to the HTML elements point: the * 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:

Screenshot 2024-07-07 at 19 17 50

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.

3i) Using MDX -> MDX provider section - Resulting HTML of 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.

@ChristianMurphy
Copy link
Member

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.

@wooorm
Copy link
Member

wooorm commented Jul 8, 2024

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:

The only people I am aware of that brought this up was people migrating.

  1. copying and pasting HTML

This is not a goal, as copy/pasting HTML into MDX will not work. Think about className. Or self-closing/void.
Then, copy/pasting HTMLJSX is the main reason why this is the way it is.
Humans want their MyLink for [](). Then they copy/paste some JSX in. They don’t expect that <a> they copy/pasted to turn into MyLink.

You are arguing about <video> here, an element that doesn’t naturally occur in markdown.
But the change you argue for applies to the things that do occur in markdown. Say, <p>, <h1>, <code>, <em>, <blockquote>, etc.
Where it is common for people to overwrite their markdown counterparts. But also include the “vanilla” elements in some more complex embedded JSX.

  1. tooling integrations for HTML elements eg. linting for attributes which should be there
  2. greppability in codebase

I argue this the other way around: if you are going to use a <MyVideo> component, you are likely using different props than an HTML <video>. You gain a lot by using MyVideo / YouTube. You can be much stricter. Accept fewer props. Ignore the obsolete archaic things that HTML has to support. For YouTube, you can accept an ID.
A linter will think that video is a video and not a Video.
Grepping for video or Video is the same.

  1. style preference towards usage of HTML elements instead of Markdown elements / JSX elements

Perhaps I am not 100% on what you mean, but I think this preference is wrong, it doesn’t work due to className and self-closing/void anyway? If you want HTML, you don’t need the MDX language. Markdown can have HTML in it. @mdx-js/mdx can support .md files with HTML.

with a few examples of what HTML tags are not replaced.

Which tags are (not) replaced?

+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:

I think this is getting very close to what is at the end of that section already:

The 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][toc] 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)**‡**

**‡** 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:

* If there’s a dot, it’s a member expression (`<a.b>` -> `h(a.b)`),
  which means that the `b` component is taken from object `a`
* Otherwise, if the name is not a valid identifier, it’s a literal (`<a-b>` ->
  `h('a-b')`)
* Otherwise, if it starts with a lowercase, it’s a literal (`<a>` -> `h('a')`)
* Otherwise, it’s an identifier (`<A>` -> `h(A)`), which means a component `A`

+This results in the following HTML:
+
+```html
+<h1>Hello <span style="color: tomato">Pluto</span></h1>
+```

The examples in these docs don’t focus on input -> output, for several reasons.
It becomes very verbose when you explain everything with a complete working playground. Those have benefits of course. But there are places for more succinct documentation to explain concepts with pseudo-code.
I wonder what including this output would add for you. What else could come out?

-The following keys can be passed in `components`:
+The following keys can be passed in a `components` object:

For me “keys in x” already implies object, I don’t think this change is needed?

-* HTML equivalents for the things you write with markdown such as `h1` for
-  `# heading` […]
+* Markdown syntax-generated HTML elements eg. if you write `# heading` in your MDX file,
+  the key is `h1` […]

I don’t think your change is an improvement.
What do you attempt to say?
(note: i also respond to this in a bullet below)

- (see [§ Table of components][toc] for examples)
+ (this does not include all HTML, see [§ Table of components][toc] for examples)

I don’t think the change is correct. There is a previous sentence: it does include all HTML equivalents for the things you write with markdown.

+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: () => { ... }`

Well, a) I really don’t consider this a “caveat”, and, b) I believe this duplicating what comes after:

**‡** 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:

* If there’s a dot, it’s a member expression (`<a.b>` -> `h(a.b)`),
  which means that the `b` component is taken from object `a`
* Otherwise, if the name is not a valid identifier, it’s a literal (`<a-b>` ->
  `h('a-b')`)
* Otherwise, if it starts with a lowercase, it’s a literal (`<a>` -> `h('a')`)
* Otherwise, it’s an identifier (`<A>` -> `h(A)`), which means a component `A`

This “caveat” is a fundament of JSX: how to differentiate between a reference to a variable and a literal tag name.

Perhaps we can illustrate that section by following it with an example of this sort:

A markdown [link](https://alpha.com),
a regular lowercase JSX element <a href="https://bravo.com">link</a>, and
a JSX component <MyLink href="https://charlie.com">link</MyLink>.

…and then with:

a(props) { return <a {...props} style={{color: 'red'}} /> },
MyLink(props) { return <a {...props} style={{color: 'blue'}} /> }

…and then show the generated HTML? Perhaps even rendered (red, mdx link color, blue)?

some of which are invalid eg. video

It’s not that video is “invalid”. MDX works with plugins. Plugins could make that video “valid”. It’s more that, as described above, whether a does something, depends on things.

  • the first bullet point starts with 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 syntax

I dunno, the second word is “equivalent”. And then there’s a whole sentence.
The first words of each bullet here relate to the “key” concept in the introductory sentence.
Changing this one breaks that sentence, and then this list.
The first thing is an HTML tag name. Rest of the sentence explains which ones.

  • there is no mention of any exceptions to HTML, except for the link that goes to a different page

That’s because <a>/<video> are not covered by this bullet. They are covered by the last bullet point. Which has a footnote.

  • there is no mention of what users cannot use in the components object keys

No “disallowlist” is needed because there’s only “allowlist”s. There are cases where <video> or <x> can be used. The first point references valid HTML tag names, second id just wrapper, last catchall last references valid JavaScript identifier.

  • there is no suggestion of what users do if they run into the limitation of <video>

I described this in more depth already but in short: how to use references in JSX (MyVideo) is explained in the rules.

unrelated to the HTML elements point: the * 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

Ok, I think this one is fine.

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.

Same as the above. I don’t think output is needed; This section isn’t about the input, or the components, or the output. It’s about whether components work. How to use <Readme />. Not what’s inside it. Or what it results in.

@karlhorky
Copy link
Contributor Author

karlhorky commented Jul 8, 2024

We don't need to go over the reasons for why to use <video> - I don't have strong feelings or opinions here yet because I haven't heavily used this.

I have a gut feeling that the rebuttals of my reasons are not necessarily taking in the complete picture, but then again, it's possible that you just have more experience than me with these things and have already gone down these roads far enough to see more.

Given more usage of <video> or other HTML tags, I may have other reasons or feel more strongly about the reasons I wrote and be able to argue for them better.

Added Explicitness, Complete Examples

with a few examples of what HTML tags are not replaced.

Which tags are (not) replaced?

I wonder what including this output would add for you. What else could come out?

For me “keys in x” already implies object, I don’t think this change is needed?

I think this is getting very close to what is at the end of that section already:

  • there is no mention of what users cannot use in the components object keys

No “disallowlist” is needed because there’s only “allowlist”s. There are cases where <video> or <x> can be used. The first point references valid HTML tag names, second id just wrapper, last catchall last references valid JavaScript identifier.

I think it's all the same answer for these: the examples and additional explicitness are meant to be aids to help make the concepts concrete for learners.

My reasoning is in my experience of seeing that explaining one thing one way, in terse writing and only partially (even if it can be explained eg. in this issue as being a full explanation) will lead to misunderstandings and half-formed knowledge.

To the "partially" point:

  1. I don't think the examples offer a full explanation without the result
  2. teaching this more completely would be both an "allowlist" and some examples in a "disallowlist"

Restructuring / Added Explicitness with Misunderstanding Potential

  • the first bullet point starts with 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 syntax

I dunno, the second word is “equivalent”. And then there’s a whole sentence. The first words of each bullet here relate to the “key” concept in the introductory sentence. Changing this one breaks that sentence, and then this list. The first thing is an HTML tag name. Rest of the sentence explains which ones.

  • there is no mention of any exceptions to HTML, except for the link that goes to a different page

That’s because <a>/<video> are not covered by this bullet. They are covered by the last bullet point. Which has a footnote.

Some sections and bullets feel like they have high potential for misunderstanding, including the bullet about HTML-equivalent elements. Restructuring the bullet text to start with a different word than "HTML" and adding a caveat are 2 ways to be explicit to avoid misunderstandings.

Alternative "caveat" suggestion

This “caveat” is a fundament of JSX: how to differentiate between a reference to a variable and a literal tag name.

Perhaps we can illustrate that section by following it with an example of this sort:

A markdown [link](https://alpha.com),
a regular lowercase JSX element <a href="https://bravo.com">link</a>, and
a JSX component <MyLink href="https://charlie.com">link</MyLink>.

…and then with:

a(props) { return <a {...props} style={{color: 'red'}} /> },
MyLink(props) { return <a {...props} style={{color: 'blue'}} /> }

…and then show the generated HTML? Perhaps even rendered (red, mdx link color, blue)?

An example would definitely help and at least partly achieve many of the things I'm aiming to with these suggestions 👍

Complete Playground

It becomes very verbose when you explain everything with a complete working playground.

I don't mean to suggest a full playground here - I'm suggesting showing the output, which is the step in between which these examples are missing.

Suggestions to Use Components

  • there is no suggestion of what users do if they run into the limitation of <video>

I described this in more depth already but in short: how to use references in JSX (MyVideo) is explained in the rules.

I don't think there's a suggestion anywhere that <Video> should be used instead of <video> (or any other example of HTML tags like this).

Having an explicit, blessed suggestion for using <Video> instead of <video> or <Img> instead of <img> (and why) would avoid users reading through issues or asking.

But maybe this actually is even bigger than I'm thinking and needs its own section, with use cases:

  1. When should I use Markdown syntax? examples/upsides/downsides (downsides include not being able to express things like <video> and not having custom functionality)
  2. When should I use HTML syntax? examples/upsides/downsides (downsides include remark/rehype plugins accessing the element and not having custom functionality)
  3. When should I use component syntax? examples/upsides/downsides (downsides include remark/rehype plugins not acting on these elements)

This actually is kind of similar to what is above in your suggestion in "Alternative "caveat" suggestion", wonder if these could be combined... 🤔

@ChristianMurphy
Copy link
Member

ChristianMurphy commented Jul 8, 2024

We don't need to go over the reasons for why to use

I have a gut feeling that the rebuttals of my reasons are not necessarily taking in the complete picture, but then again, it's possible that you just have more experience than me with these things and have already gone down these roads far enough to see more.

Given more usage of

I don't think there's a suggestion anywhere that

I think it's all the same answer for these: the examples and additional explicitness are meant to be aids to help make the concepts concrete for learners.

There is hierarchy to this solution space

There are a lot of ways to solve an issue like this.
Plain <video> is fine, and can be used with fully qualified urls/domains and absolute paths, which work regardless of where they on your site.
💡 use the platform first

If you want more features/customizations in how a video is rendered.
Components are supported like <Video>
💡 if you don't use the platform, use the framework

If for some reason you choose not to use the platform or the framework, then yes, using MDX advanced internals you can change how the content works.
This is not a beginner topic, generally not a good idea, and should not be labelled as a recommended beginner approach.

You very well may have a valid use case for it, I appreciate and respect that.
That does not mean everyone should do the same thing.

style preference towards usage of HTML elements instead of Markdown elements / JSX elements

Then use HTML, don't turn standard HTML elements into something custom.
That is what HTML custom elements and React Components are for.

@ChristianMurphy
Copy link
Member

But maybe this actually is even bigger than I'm thinking and needs its own section, with use cases:

  • When should I use Markdown syntax? examples/upsides/downsides (downsides include not being able to express things like
  • When should I use HTML syntax? examples/upsides/downsides (downsides include remark/rehype plugins accessing the element and not having custom functionality)
  • When should I use component syntax? examples/upsides/downsides (downsides include remark/rehype plugins not acting on these elements)

This feels more appropriate

wooorm added a commit that referenced this issue Jul 9, 2024
wooorm added a commit that referenced this issue Jul 9, 2024
@wooorm
Copy link
Member

wooorm commented Jul 9, 2024

Removed the asterisk in 90f509b.

An example would definitely help and at least partly achieve many of the things I'm aiming to with these suggestions 👍

Done in 044e8b2.

Further responses to most of your comments.


I don't have strong feelings or opinions here yet because I haven't heavily used this.

I have a gut feeling that the rebuttals of my reasons are not necessarily taking in the complete picture

This sounds contradictory. You haven’t used this much but we are the ones missing the complete picture. 😅
I do have experience using it; listening to different humans; coming up with arguments; changing it; defending it. It could definitely be that I don’t know your complete picture yet, feel free to explain it more in-depth.
I believe that when you use JSX more, you will feel similar.

the examples and additional explicitness are meant to be aids to help make the concepts concrete for learners.

I think there’s also a trade off here. My argument goes similar to how I argued for science papers somewhere else: one does not get far if one constantly has to explain every concept in detail, so that it can be understood by beginners, that don’t read the surrounding text. More text costs every reader too.
There is an alternative: different docs explainings different things. Docs building on each other. Different styles of articles (i.e., the docs vs the guides). A good playground where people can play and see.

My reasoning is in my experience of seeing that explaining one thing one way, in terse writing and only partially (even if it can be explained eg. in this issue as being a full explanation) will lead to misunderstandings and half-formed knowledge.

To the "partially" point:

I don't think the examples offer a full explanation without the result
teaching this more completely would be both an "allowlist" and some examples in a "disallowlist"

These are broad statements. There are of course cases where they can be implemented. But there might be cases where I don‘t think it’s needed. I’d appreciate it when they can be made concrete: which concepts are explained a singular way? I may be able to point to other docs that explain it other ways. Or more completely.

Particularly regarding the “will lead to misunderstandings and half-formed knowledge” part: I believe this to be inevitable for learners. Not even for just for the beginners, that grow (and can only grow due to it). But anyone reading a sentence once will have misunderstandings and half-formed knowledge. Anyone only reading theory and not putting it into praxis will misunderstand.

Restructuring the bullet text to start with a different word than "HTML" and adding a caveat are 2 ways to be explicit to avoid misunderstandings.

I fail to see this. I don’t see a problem here nor an improvement in the suggestion: these values for keys do come from the HTML spec. Not RSS or SVG or JS or CSS. p, strong, h1, td are HTML equivalent to things in markdown. I don’t see how this concept can be explained differently.

Perhaps reading through the earlier document “What is MDX?” might be useful in clearing up what HTML syntax / JSX syntax mean, in relation to MDX?

I don't mean to suggest a full playground here - I'm suggesting showing the output, which is the step in between which these examples are missing.

The output is missing for all these examples, in this document and in “What is MDX?”, because it doesn’t matter what the output is here. So I am extrapolating what you are asking for: if here, why not everywhere? If output, why not a package.json, or entire playgrounds?

I don't think there's a suggestion anywhere that <Video> should be used instead of <video> (or any other example of HTML tags like this).

Having an explicit, blessed suggestion for using <Video> instead of <video> or <Img> instead of <img> (and why) would avoid users reading through issues or asking.

It’s not there because I don‘t think that question is for that spot. There is an explanation of the difference between h1 and Component. And now there’s an illustration of []() vs a vs Link. But when to use <video>, as christian mentions, has more to do with the web, choosing <Video> has more to do with React. That <video> and <Video> are two things is about JSX.
I think this section is more about the difference. Not about tips on what one should choose in different circumstances.

But maybe this actually is even bigger than I'm thinking and needs its own section, with use cases:

When should I use Markdown syntax? […] / When should I use HTML syntax? […] When should I use component syntaxJSX syntax? […]

Sure. How to use MDX at scale. How to enjoy writing MDX. MDX patterns. Stuff like that could all be its own guides. They are more tied to personal opinions. And presumably also more tied to a particular platform or a framework. So where it goes depends on what you want to suggest!

@wooorm
Copy link
Member

wooorm commented Jul 9, 2024

Coming back to the original issue, I think this can be closed.

  1. at step 5, I believe OP should’ve considered the difference between HTML and JSX (as described in What is MDX?) and the difference between video and Video in JSX (which is also described in What is MDX?); it is understandable of course that OP went down rabbit holes and found old issues, but both are alluded to/shown/explained in docs already, I wonder if mentioning it more often would’ve prevented going into old issues
  2. the root of the problem OP ran into, as discussed in the other discussion, has I believe more to do with Webpack/Next.js than with video and Video or with compilers and plugins. As the following worked:
    import myVideoSource from './some-video.mp4'
    
    <video src={myVideoSource} controls />
  3. several concrete improvements were discussed and I implemented 90f509b and 044e8b2. Improvements to these changes, and also the ideas around new guides, can go in separate discussions/issues/PRs, so that we can cover more user stories.

Do please comment when you want to add something important: comments still work on closed issues. But also consider my goal is to move to concrete improvements and discussions.

@wooorm wooorm closed this as completed Jul 9, 2024
@wooorm wooorm added the 💪 phase/solved Post is done label Jul 9, 2024
@karlhorky
Copy link
Contributor Author

Ok, thanks! The commit 044e8b2 does achieve 2 things in my perspective:

  1. Illustrates the different behavior with Markdown elements, HTML elements and JSX components
  2. Demonstrates implicitly that MDX does nothing with <a>

I think what's missing is:

  1. Showing the output as code
  2. An explicit mention that MDX doesn't modify <a>
  3. Visual formatting of the new points in the paragraph, to make it easier to scan, in a structure that visually mimics the code above
  4. An explicit text description of what MDX does with "an object mapping component names to components", using preferred terminology
    • (I still think there should be some short text in the first paragraph under "Components" - the current first paragraph "There is one special prop: components. It takes an object mapping component names to components. Take this example:" sounds to me like it's trying to avoid saying what it is for - MDX takes components, but it doesn't tell us what it's doing with that until further down. it doesn't need to be long text)
  5. The MDX team suggestion for using custom components instead of HTML elements, including HTML elements non-expressible in Markdown. Ideally of course as a few bullets instead, which Titus replied to here:

    But maybe this actually is even bigger than I'm thinking and needs its own section, with use cases:
    When should I use Markdown syntax? […] / When should I use HTML syntax? […] When should I use component syntaxJSX syntax? […]

    Sure. How to use MDX at scale. How to enjoy writing MDX. MDX patterns. Stuff like that could all be its own guides. They are more tied to personal opinions. And presumably also more tied to a particular platform or a framework. So where it goes depends on what you want to suggest!
    I'm suggesting something smaller than a guide - probably 3 short bullets similar to what Christian wrote showcasing the strengths and weaknesses of each, and highlighting that it is the suggestion of the MDX team to not use <video> or <img> but rather <Video> and <Img> in circumstances where extension of the element is wanted (and what circumstances/benefits are better for Markdown syntax instead)

  6. Mention of some Micromark workaround for users who still have a use case for HTML element overrides

    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 micromark/micromark#extending-markdown

  7. The "disallowlist" idea as a teaching tool, for breaking any misconceptions as to what cannot go in the components keys (HTML literal elements and those which cannot occur in Markdown)

I opened a PR for 1 (I originally suggested HTML, but I kept JSX for the output), 2, 3 and 4 for first feedback:

Because the rest of the points seem lower likelihood to be accepted, I have held off with creating a PR for those.

@ChristianMurphy
Copy link
Member

Showing the output as code

There are a lot of different outputs.
This may be a case for having embedded playgrounds elsewhere in the site.
https://mdxjs.com/playground/

An explicit mention that MDX doesn't modify <a>

I'm a bit cautious about starting a dumping ground of all the things MDX doesn't do.
Which is infinite.

Visual formatting of the new points in the paragraph, to make it easier to scan, in a structure that visually mimics the code above

Improved formatting is welcome!

The MDX team suggestion for using custom components instead of HTML elements, including HTML elements non-expressible in Markdown

I'd second Titus' point here.
Markdown is a language, people can use the parts of the syntax they want.
There isn't necessarily a suggestion of "don't use HTML".
It would be more valuable to articulate trade offs of Markdown, HTML, Custom Elements, and plugins/content level manipulation. So that adopters can make an informed decision.

Mention of some Micromark workaround for users who still have a use case for HTML element overrides

Not quite what I was getting across here.
Micromark is even lower level than working on the syntax tree.
I'm more getting at documenting how to do some different types of content manipulation with plugins.
But tying into the point above, making users aware of the complexity and trade offs, so new users have an idea what they are getting into.

The "disallowlist" idea as a teaching tool, for breaking any misconceptions as to what cannot go in the components keys (HTML literal elements and those which cannot occur in Markdown)

It feels like this may be best at the type level first.
Perhaps leveraging something like https://www.typescriptlang.org/play/?#code/PTAEFEDsGcFcCcCm1QBcAWjQDMCW9pVQBjdAQ3jONUXlFxVgAcnbizpEAoVAT1dABJaAFUWbDogA8AZVCIAHjUgATFIXi5IAcwB8oALyg5i5WtBjW8dp1n6A-GniwsALhxkANpwDcXLiAQMAjIaJigGlraEagUqCgA7rgYoGQkZEzJXqCeiKg08Dz8WDKx8PEA6snoAMIZWZ6y8kqIquqomjr6RiYtbaAABgAkAN5a2LSgAGIAvqPjkwBKMwNcoKCOwpYStlP6pq3mHS5r6xvGp+vukIgAbrSn13e0fgFgAGpeuCrNZAC2TFyRQEAHEkHkooZjGVKtU6plYo0AOQACUQnk8AHskbofKBAgAVYqgVHorFI-yBQSQW5fH6Kf6ArAACmg6ExsE8PwARlgkTd7vAkQBKYFYam0zzfMGICE6KGlOLQKoYeENKRIzAY7G4-FgIkCfnPIWU-XIVCQpIpKioWDZWmaMjc3LQLjETEwIiS6Xgi06dwyuXRIyk7VIvGE9AMegoPA3N0ewj0Gl0wN+7TuCWp32QkNa8kR-VR9Tszk-diwTipUAGxAyYiaJhEWjwTGFIA /cc @remcohaszing

@wooorm
Copy link
Member

wooorm commented Jul 10, 2024

  1. Showing the output as code

This is intentionally omitted. I mentioned in previous comments why I don’t believe the output is not relevant here. As Christian mentions, to MDX, there are also infinite outputs. And, it’s explained in a preview and prose already (next point). Christian mentions this too.

  1. An explicit mention that MDX doesn't modify <a>

It is explicitly described in the paragraph after.

  1. Visual formatting of the new points in the paragraph, to make it easier to scan, in a structure that visually mimics the code above

Perhaps I don’t know what you mean. The following paragraph does describe visual formatting. Do you mean using those colors and borders in the text as well? That doesn’t feel good. When you highlight everything, nothing is highlighted.

  1. An explicit text description of what MDX does with "an object mapping component names to components", using preferred terminology
    • (I still think there should be some short text in the first paragraph under "Components" - the current first paragraph "There is one special prop: components. It takes an object mapping component names to components. Take this example:" sounds to me like it's trying to avoid saying what it is for - MDX takes components, but it doesn't tell us what it's doing with that until further down. it doesn't need to be long text)

I don’t believe it’s needed here: I am sure you are aware of “show, don’t tell”; and repetition has also already been noted in the discussions too. Showing and then telling seems fine. I don’t see what tell then show then tell again adds.

  1. The MDX team suggestion for using custom components instead of HTML elements, including HTML elements non-expressible in Markdown. Ideally of course as a few bullets instead, which Titus replied to here: […]
    • I'm suggesting something smaller than a guide - probably 3 short bullets similar to what Christian wrote showcasing the strengths and weaknesses of each, and highlighting that it is the suggestion of the MDX team to not use <video> or <img> but rather <Video> and <Img> in circumstances where extension of the element is wanted (and what circumstances/benefits are better for Markdown syntax instead)

I don’t really see it. Strengths and weaknesses. Here. MDX supports markdown and JSX. What you subjectively think is a great idea in your current stack has little to do with MDX. Perhaps you are looking for “What is MDX”.

I am open, like Christian, to a guide or similar somewhere on when to choose Markdown/HTML/custom elements/plugins/transforms/syntax extension.

  1. Mention of some Micromark workaround for users who still have a use case for HTML element overrides

Christian’s answer is sufficient here I believe.

  1. The "disallowlist" idea as a teaching tool, for breaking any misconceptions as to what cannot go in the components keys (HTML literal elements and those which cannot occur in Markdown)

Anything is possible there.
I think you are looking for the table of components, which is already linked: https://mdxjs.com/table-of-components/. It doesn’t contain video.
At the bottom of the table, it mentions that plugins could add support for anything (also video).

@karlhorky
Copy link
Contributor Author

karlhorky commented Jul 10, 2024

With "visual formatting" I mean making the prose visually structured and designed like the code it's describing, making it easier to scan and match up with the code while looking back and forth between the code and prose. Since there are 3 JSX elements, I added 3 bullet points.

The idea behind it: the visual shape of the prose and code in writing and docs is important for scanning, making it inviting and not burying info (also which word starts a line or sentence).

I don’t believe it’s needed here: I am sure you are aware of “show, don’t tell”; and repetition has also already been noted in the discussions too. Showing and then telling seems fine. I don’t see what tell then show then tell again adds.

Right, I think this is where a key disagreement (which appears unresolvable) is - in my (strong) opinion coming from lots of observation, repetition is very useful for beginners, and has only the downside of taking up space, which I'm trying to minimize with keeping it short. Terseness and purity are good for the authors (less to produce) and maybe for making it more visually minimal, but the downsides are bigger - that it doesn't get the point across.

Probably my opinion and suggestions and style for teaching beginners is just incompatible with the MDX style, so I think me contributing less is the best choice here. It feels insurmountable to introduce change to the current MDX style. I'll still do small PRs as they come up but I'll keep in mind that the method of teaching is probably not going to change.

What you subjectively think is a great idea in your current stack has little to do with MDX

Interesting, what are the biggest, most popular uses and consumers of MDX? I thought for sure it would be the React ecosystem, haven't seen it in big projects elsewhere.

I don't really have a strong opinion on where it should go in the docs, but at the point that the concept of component replacement is being introduced (which is where I'm suggesting it go), I would expect a small overview of those "best practices" from the MDX team to be introduced (maybe linked to another short guide somewhere). As of now, these best practices are buried in issues. So even putting it somewhere non-ideal would be an improvement in visibility.

@wooorm
Copy link
Member

wooorm commented Jul 10, 2024

repetition is very useful for beginners

Sure. There is already repetition. By this logic 5 or 20 repetition is an improvement.

Interesting, what are the biggest, most popular uses and consumers of MDX? I thought for sure it would be the React ecosystem, haven't seen it in big projects elsewhere.

I don’t think that’s relevant. Not only the biggest mass of beginners deserves docs on this website. You are free to teach only React beginners. There are React-specific docs here. It’s also used in many examples. But it’s not the focus. By this logic we should drop React on this website for PHP or Rails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💪 phase/solved Post is done
Development

No branches or pull requests

3 participants