Personnalisation de React-Markdown en Typescript

Personnalisation de React-Markdown en Typescript

Alexandre P. dans Dev - Le 13-06-2022

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

#react#react-markdown#typescript#conseils#programming

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