#Add `data-*` attribute to a markdown fenced codeblock

35 messages · Page 1 of 1 (latest)

hollow wyvern
#

I have codeblocks like the following:

~~~ts
import { foo } from 'bar';

export default foo;
~~~

And I'd like to add some metadata to the rendered <code> or <pre>, like a data-filename to be able to use that in CSS and client JS.

(Just pretend the ~~~ were backticks, but discord can't nest codeblocks it seems)

tiny breach
hollow wyvern
#

I want the content of the data-* attribute be controllable from the fences.

~~~ts filename="reexport.ts"
import { foo } from 'bar';

export default foo;
~~~

Would create data-filename="reexport.tx" on the <code> or <pre>.

hollow wyvern
#

When I try this, the extra info seems to be ignored, though at least on a quick glance, the file type is still taken correctly

wraith temple
hollow wyvern
#

I'm not strictly bound to the syntax. I will check the rehype plugin you suggested.

hollow wyvern
#

I have no clue how to add that…

<!-- rehype:foo=bar --> in the MDX causes a compile error:

[plugin:@mdx-js/rollup] Unexpected character `!` (U+0021) before name, expected a character that can start a name, such as a letter, `$`, or `_` (note: to create a comment in MDX, use `{/* text */}`)

The plugin is added like this:

diff --git a/astro.config.mjs b/astro.config.mjs
index 203db25..770543d 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -2,6 +2,8 @@ import { defineConfig } from 'astro/config';
 import mdx from '@astrojs/mdx';
 import robotsTxt from 'astro-robots-txt';
 
+import rehypeAttrs from 'rehype-attr';
+
 import path from 'path';
 
 import tailwind from '@astrojs/tailwind';
@@ -21,9 +23,13 @@ const alias = {
 
 const external = ['svgo'];
 
+const mdxConfig = {
+       remarkPlugins: [rehypeAttrs],
+};
+
 // https://astro.build/config
 export default defineConfig({
-       integrations: [sitemap(), mdx(), tailwind(tailwindConfig), robotsTxt()],
+       integrations: [sitemap(), mdx(mdxConfig), tailwind(tailwindConfig), robotsTxt()],
        site: 'https://blog.nobbz.dev',
        vite: {
                ssr: { external },
timber dove
#

They recommend using JSX comment syntax -

{/* rehype:foo=bar */}
#

Not sure whether that JSX comment gets outputted as html for the the rehype plugin to parse.

#

I just noticed, the error messages actually tells us what to do

(note: to create a comment in MDX, use `{/* text */}`)
#

So, if you don't really need an MDX file, you could try the rehype comment in a regular md file and see whether the plugin gives you what you need.

hollow wyvern
#

As I use astro components I have to use mdx

#

Can shiku be used as a component? I only find that possibility mentioned for prism...

#

Or do I really need to figure out how @astro/mdx works and make a pr? mdx itself already seems to properly parse the metadata

thorn sun
#

I recommend creating a dedicated <CustomCode> which is wrapping the built-in Astro <Code> component for passing props.
Other methods (using comments or magic string) are less idiomatic of MDX

hollow wyvern
#

I tried it.

Using <Code> looks ugly, takes away the hihglighting of the code block within VScode, and the provided attributes wont end up in the HTML anyway 😦

thorn sun
#

(gridsome-remark-embed-snippet
gatsby/gatsby-remark-embed-snippet
gatsby-remark-embed-markdown)

#

goal is to parse inside Code node and get the filename.js attribute

tiny breach
#

I made custom remark plug-in

at ./codeBlock.js

hollow wyvern
#

Thank, I will take a closer look later today!

tiny breach
#

have good day

hollow wyvern
#

Doesn't seem to work for me… Adding a console.log to inspect relevant attributes of the node (mainly type) shows that I never see nodes with type == "html".

Do I perhaps need a certain version of remark or other libs that might be older for me as I generated the project months ago and do not really understand how dependency bounds in the JS world work?

I will try to get a branch pushed to my repo later today (need to clean up some other stuff first that leaked from a draft post)

tiny breach
#

you use @astro/mdx ?

#

send your config

#

asrto.config.mjs

hollow wyvern
tiny breach
#

this should works.

/**
 * @typedef {import('mdast').Root} Root
 *
 * @typedef Options
 *   Configuration (optional).
 * @property {boolean} [someField]
 *   Some option.
 */

// To type options and that the it works with `mdast`:
import { visit } from 'unist-util-visit';

export default function remarkCodeBlock(options = {}) {
  const plugins = options.plugins || [];

  return (tree) => {
    visit(tree, (node) => {
      // console.log({ type: node.type, value: node.value });
      if (node.type == 'html' && node.value.includes('class="astro-code"')) {
        // console.log(node.value);
        // console.log(node);
        node.value = node.value.replace(
          '"astro-code"',
          '"astro-code"' +
            (node?.meta
              ? ' ' + String(node.meta).replace(/(\w+\=.*?)/g, 'data-$1')
              : '')
        );
      }
    });
  };
}
#

make sure you upgrade to @astrojs/mdx@latest.