Pourquoi choisir Tiptap comme éditeur de texte riche ?

Article rédigé par

Raphaël_Avatar
Raphaël Huiban

Développeur JavaScript

Pourquoi choisir Tiptap comme éditeur de texte riche ?

Chez Neomanis, nous avons testé plusieurs éditeurs de texte riche pour notre produit. Mais jusqu’à présent, aucun ne répondait entièrement à nos attentes.

Nous avons finalement découvert Tiptap, un éditeur de texte riche puissant et hautement personnalisable. 👌

1 – Qu’est-ce qu’un éditeur de texte riche ? 

Avant de découvrir ensemble Tiptap, prenons le temps de comprendre ce qu’est un éditeur de texte riche.

Un éditeur de texte riche, également appelé WYSIWYG (What You See Is What You Get), est un outil de traitement de texte avancé à utiliser dans une application web et qui permet à l’utilisateur de visualiser directement le résultat pendant qu’il écrit. Cela comprend l’affichage d’images, de tableaux, de titres, de liens hypertexte, de blocs de code et autres éléments de mise en forme.

💡 Il est important de noter que la qualité de l’aperçu final dépend de la qualité de l’éditeur de texte utilisé. Certains éditeurs de texte WYSIWYG peuvent produire des résultats incohérents : il peut y avoir un écart visuel entre ce que l’utilisateur a écrit et ce qui sera affiché. Il est donc essentiel de choisir un éditeur de texte riche fiable et performant pour obtenir un rendu de qualité.

2 - Aperçu des éditeurs de texte riche React 

Il existe de nombreuses bibliothèques d’éditeurs de texte riche React, la plupart étant des adaptations de bibliothèques Javascript Vanilla en React, telles que React Quill. On trouve également des bibliothèques entièrement développées autour de React, comme Draft.js ou plus récemment Lexical. Chacune d’elles présente des avantages et des inconvénients, et je vous encourage à parcourir leur documentation pour en savoir plus.

Dans notre cas, nous avons essayé d’intégrer CKEditor ainsi que React Quill. Mais malheureusement nous avons rencontré de nombreux problèmes, tels que :

  • Des difficultés pour appliquer des styles personnalisés à l’éditeur
  • L’ajout de fonctionnalités compliqué, voir impossible
  • Des problèmes de performances

3 - Présentation et caractéristiques de Tiptap 

Tiptap est une bibliothèque d’édition de texte moderne, puissante, facile à utiliser. Celle-ci utilise le même moteur en lecture qu’en écriture et se démarque sur plusieurs points forts :

✅ Framework-agnostic 

À la base, Tiptap est une librairie qui fonctionne en Javascript Vanilla. Mais il existe plusieurs adaptateurs officiels qui permettent de l’utiliser dans différents frameworks tel que React, Vue.js ou encore Svelte. À noter que la communauté Tiptap est aussi beaucoup investie. Ils ont par exemple créé les adaptateurs Angular et SolidJS.

Chez Neomanis, nous utilisons React pour nos différentes applications. Nous avons donc installer l’adaptateur React(1) ainsi que les différentes extensions dont nous avions besoin.

✅ Headless

À la vue de notre interface moderne et unique, il est très rare pour nous de trouver des librairies qui possèdent des styles prédéfinis s’intégrant correctement avec notre design ; c’est pour cela qu’utiliser cette librairie sans CSS nous permet de séparer la création et la personnalisation des composants de l’éditeur. Pour le style, nous utilisons TailwindCSS(2).

Alors en pratique, je vous propose l’exemple d’une barre de menu de l’éditeur (créée de zéro) intégrant un bouton pour activer/désactiver le gras du texte sélectionné :

import { Editor } from "@tiptap/react";  
import { faBold } from "@fortawesome/free-solid-svg-icons";  
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";  
import { classNames } from "./utils";  

// We pass in props the editor that comes from the useEditor of @tiptap/react
export default function BoldButton({ editor }: { editor: Editor }) {  
    return (  
        <button  
            type="button"  
            // We can perform several actions thanks to .chain()
            // Here we focus the editor after clicking on the button with .focus()
            // Then enable/disable bold with .toggleBold()
            // Finally we run the commands with .run()
            onClick={() => editor.chain().focus().toggleBold().run()}  
            // We deactivate the button if the selected text cannot perform the action following the .can()
            disabled={!editor.can().chain().focus().toggleBold().run()}  
            className={classNames(  
                "h-12 w-8 flex items-center justify-center",  
                // Depending on the state of the selected text, we display a different style on the button with different tailwindCSS classes
                editor.isActive("bold") ? "text-neo-blue" : "text-white"  
            )}  
        >  
            <FontAwesomeIcon icon={faBold} />  
        </button>  
    );  
}  

✅ Modulable 

Tiptap est construit autour d’une architecture modulaire. Cela signifie qu’on installe uniquement ce qu’on utilise. C’est un gain non-négligeable au niveau des performances. Grâce à cette architecture, nous pouvons créer des extensions personnalisées(3) pour apporter de nouvelles fonctionnalités à notre éditeur de texte !

Un deuxième exemple : en partant de l’extension alignement de texte (TextAlign), j’ai créé une nouvelle extension qui s’appliquera aux images.

Cette nouvelle extension se décompose en 3 parties :

1️⃣ Création de l’extension CustomImage (à partir de l’extension Tiptap Image).

import { ReactNodeViewRenderer } from "@tiptap/react";  
import Image from "@tiptap/extension-image";  
import CustomImageNode from "./CustomImageNode";  

export const CustomImage = Image.extend({  
    // We name our extension so that we can use it later
    name: "customImage",  
    // We add a custom React component as to display the extension
    addNodeView() {  
        return ReactNodeViewRenderer(CustomImageNode);  
    },  
});  

2️⃣ Création du composant React CustomImageNode.

import { NodeViewWrapper, NodeViewProps } from "@tiptap/react";  
import { classNames } from "@/utils";  

export default function CustomImageNode({ node }: NodeViewProps) {  
    return (  
        // We just add our css as well as a custom attribute that will be applied by the CustomTextAlign extension
        <NodeViewWrapper className={classNames("flex", node.attrs.justifyContent)}>  
            {/* We add the data attribute used by Tiptap for draggable elements */}  
            <img data-drag-handle {...node.attrs} />  
        </NodeViewWrapper>  
    );  
}  

3️⃣ Création de l’extension CustomTextAlign (à partir de l’extension Tiptap TextAlign).

import TextAlign from "@tiptap/extension-text-align";  

// We create an object with the values used by the TextAlign extension as keys
// And in values the tailwind classes that we would like to apply accordingly
const textAlignFlexMap = {  
    left: "justify-start",  
    center: "justify-center",  
    right: "justify-end",  
    justify: "justify-center",  
};  
  
export const CustomTextAlign = TextAlign.extend({  
    addGlobalAttributes() {  
        return [  
            // We retrieve the attributes already used by the extension
            ...this.parent?.(),  
            {  
                // We just add the attribute justifyContent, applied by the extension and which is used in our Custom Image 
                types: this.options.types,  
                attributes: {  
                    justifyContent: {  
                        default: textAlignFlexMap[this.options.defaultAlignment],  
                        rendered: false,  
                    },  
                },  
            },  
        ];  
    },  
    addCommands() {  
        return {  
            // We retrieve the commands already used by the extension  
            ...this.parent?.(),  
            // We replicate the basic behavior of the setTextAlign command 
            setTextAlign:  
                (alignment: string) =>  
                ({ commands }) => {  
                    if (!this.options.alignments.includes(alignment)) {  
                        return false;  
                    }  
                    
                    return this.options.types.every((type) =>  
                        commands.updateAttributes(type, {  
                            textAlign: alignment,  
                            // And we modify the setTextAlign command to apply the new attribute justifyContent  
                            justifyContent: textAlignFlexMap[alignment],  
                        })  
                    );  
                },  
        };  
    },  
});  

4 - Conclusion

Il est vrai que Tiptap demande un peu plus de travail lors de son implémentation que d’autres librairies d’éditeur de texte riche (qui viennent avec beaucoup de fonctionnalités déjà prêtes). Mais le gain en performance, la facilité à modifier le visuel, l’intégration facile avec TailwindCSS et la possibilité de pouvoir créer et intégrer nos propres fonctionnalités dans l’éditeur font de Tiptap notre éditeur de texte riche de préférence.

😉 Merci d’avoir lu cet article et j’espère qu’il aura attisé votre curiosité concernant Tiptap !

5 - Ressources

Articles qui pourraient vous plaire

Suivez-nous sur les réseaux sociaux

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut