Personnalisation de React-Markdown en Typescript
React-Markdown est une librairie d'interprétation de contenu markdown qui permet de générer automatiquement le code HTML. Cependant, il génère des balises standards, sans classes et les affiche. Si vous voulez personnaliser tout ça, il faudra créer votre CSS en fonction de l'élément parent. Nous allons voir comment créer nos propres renderer pour les composants HTML avec react-markdown en typescript.
Une meilleure association Strapi Next.js
Lorsque vous rédigez vos articles avec Strapi, un input de type RichText se contentera de générer du texte au format Markdown. Pour pouvoir l'afficher avec la mise en forme, côté Next.js, nous allons utiliser un composant React : React-Markdown.
A quoi sert cette librairie ?
Elle remplace le Markdown généré par Strapi en composants HTML plus traditionnel.
Des
<H1> <H2> <H3>
pour les titres,
des
<A>
pour les liens,
des
<UL>
pour les listes...
Cette librairie est personnalisable à souhait. On peut remplacer pour chaque élément HTML rendu par un composant custom et la documentation nous montre comment nous y prendre :
import React from 'react'
import ReactDOM from 'react-dom'
import ReactMarkdown from 'react-markdown'
import MyFancyRule from './components/my-fancy-rule.js'
ReactDOM.render(
<ReactMarkdown
components={{
// Use h2s instead of h1s
h1: 'h2',
// Use a component instead of hrs
hr: ({node, ...props}) => <MyFancyRule {...props} />
}}
>
# Your markdown here
</ReactMarkdown>,
document.querySelector('#content')
)
En JSX cela ne pose aucun problème, mais en TSX c'est une autre pair de manches...
Comment se fait la surcharge de React-Markdown
On passe un objet à la propriété components, et chaque clé de cet objet représente un composant. Le problème, c'est que le renderer est une fonction et cela pose pas mal de problème pour pouvoir typer ces éléments.
Voici comment j'ai procédé :
Je commence par créer mon composant MarkdownLink qui retourne un JSX.Element basique :
import * as React from 'react'
type MarkdownLinkProps = {
href: string
children: React.ReactNode
}
const MarkdownLink = ({ href, children }: MarkdownLinkProps) => {
return (
<a href={href} target="_blank" rel="noreferrer">
{children}
</a>
)
}
export default MarkdownLink
Puis au moment du render de React-Markdown :
<ReactMarkdown
components={{
a: ({ node, children }) => {
return (
<MarkdownLink href={(node.properties?.href as string) ?? ''}>
{children[0]}
</MarkdownLink>
)
},
}}
>
{post.attributes.content}
</ReactMarkdown>
Et voilà, notre composant remplace désormais la balise standard généré par React-Markdown. 😉
Alexandre P.
Développeur passionné depuis plus de 20 ans, j'ai une appétence particulière pour les défis techniques et changer de technologie ne me fait pas froid aux yeux.