Difficulté : Expert · Temps estimé : 3 à 6 mois pour un clone complet (2 à 4 semaines pour un prototype avec les blocs de base)
+Quick Guide
+-
+
- Définir le modèle de données orienté bloc avec un arbre parent-enfant. +
- Mettre en place un moteur de rendu par bloc, piloté par le contenu et les propriétés. +
- Implémenter la commande slash (
/) et le menu contextuel de transformation.
+ - Gérer le formatage texte via quatre modes : saisie Markdown WYSIWYG, raccourcis clavier, barre d’outils flottante, commandes de couleur. +
- Intégrer le glisser-déposer avec indices fractionnels et indentation visuelle. +
- Appliquer rigoureusement le Design System de Notion (couleurs, typographie, espacements, ombres, animations). +
- Construire les blocs avancés : bases de données, vues (table, board, calendar…), propriétés typées. +
- Ajouter la collaboration temps réel avec CRDT et indexation fractionnelle. +
Prérequis
+-
+
- Maîtrise de React (ou vue similaire) et de la gestion d’état complexe. +
- Connaissance des éditeurs de texte (contentEditable, IME, décorations) ou d’une bibliothèque comme Slate.js / ProseMirror. +
- Compréhension des algorithmes CRDT (Yjs, Automerge) et des index fractionnels pour le classement. +
- Expérience avec le glisser-déposer HTML5, les listes virtualisées et les animations CSS. +
- Accès aux ressources de conception : tokens de couleurs, typographie, ombres de Notion (cf. sources). +
++Tip: Téléchargez les polices NotionInter et JetBrains Mono pour reproduire exactement le rendu typographique.
+
+
Étape 1 : Modéliser l’arbre de blocs
+L’unité fondamentale de l’éditeur Notion est le bloc. Chaque bloc possède un identifiant unique (id), un type (paragraphe, titre, image, etc.), des props spécifiques (texte, URL, fichier, propriétés de base de données…), un objet style (couleur de texte, fond) et un tableau ordonné d’IDs d’enfants (children). L’ordre global des blocs au sein d’une page est maintenu par un index fractionnel – une chaîne comme "a0", "a1b" – qui permet d’insérer de nouveaux blocs entre deux positions sans réindexer l’ensemble (Frontend System Design).
Définissez votre structure de données de base :
+interface Block {
+ id: string;
+ type: 'paragraph' | 'heading_1' | 'heading_2' | ... ;
+ props: any; // texte, url, etc.
+ style?: { textColor?: string, bgColor?: string };
+ parentId: string | null;
+ children: string[];
+ fractionalIndex: string; // position dans la liste ordonnée
+}
+Chaque page est un bloc racine dont les enfants sont les blocs de premier niveau. L’indentation est matérialisée par la relation parent-enfant : un bloc indenté (appuyer sur Tab) devient enfant du bloc précédent, ce qui lui confère un retrait visuel et une ligne verticale de liaison.
+++Warning: Ne stockez pas le texte formaté en HTML. Conservez une représentation interne avec les marqueurs Markdown bruts (
+**gras**) que vous masquez à l’affichage pour obtenir l’effet WYSIWYG immédiat. Cela garantit une exportation Markdown propre.
+
Étape 2 : Rendre les blocs et gérer l’édition
+
Chaque type de bloc est un composant React capable de passer du mode lecture au mode édition (en utilisant contentEditable pour la portion texte). Pour les blocs de texte, le composant affiche le contenu avec les décorations de formatage (gras, italique, code) tout en masquant les symboles Markdown sous-jacents.
-
+
- Titres (H1, H2, H3) : la détection du marqueur (
#,##,###) déclenche la transformation immédiate du bloc en titre. Visuellement, le texte est rendu avec les spécifications typographiques : H1 à 40px Bold, H2 à 32px Bold, H3 à 26px Semibold (Notion Design Tokens).
+ - Listes (à puces, numérotées, to-do) : un pattern en début de ligne (
*,-,+,1.,[]) transforme le bloc. La numérotation est automatique, gérée par un compteur dans le composant parent.
+ - Togglers : le premier enfant sert de contenu dépliable. L’icône de flèche pivote avec une animation CSS de 200ms
ease-in-out.
+
La virtualisation est critique : seuls les blocs dans la zone visible de la fenêtre sont montés dans le DOM. Utilisez une bibliothèque comme react-window en estimant la hauteur de chaque type de bloc. Les blocs hors écran sont remplacés par des espaceurs vides pour éviter les défilements saccadés.
++Tip: Intégrez un état « placeholder » : quand un bloc vide a le focus, affichez un texte grisé du type « Titre 1 » ou « Liste à puces… » en utilisant la couleur
+#9B9A97.
+
Étape 3 : La commande slash et le menu de transformation
+Taper / dans un bloc vide ou en début de ligne après un espace ouvre un menu flottant ancré sous le curseur. Ce menu liste tous les types de blocs et actions (insertion de médias, changement de couleur, bouton de modèle…). Son implémentation doit :
-
+
- Afficher une popup avec largeur ~300px, ombre portée
md(0 4px 16px rgba(0,0,0,0.08)), rayon de bordure 8px.
+ - Permettre une recherche incrémentale qui met en surbrillance les correspondances. +
- Catégoriser les résultats (Basique, Média, Base de données, Avancé) avec des icônes, reproduisant exactement l’interface de Notion. +
Le choix d’un élément dans le menu transforme le bloc courant ou en insère un nouveau. La commande slash accepte aussi des alias de couleur : /red, /blue, /default, etc., pour modifier directement le fond ou le texte du bloc (Markdown Commands & Editing Shortcuts).
++Warning: Gérez la composition IME pour les langues asiatiques. Ne déclenchez pas la commande slash en plein milieu d’une saisie en cours de composition, sinon vous briserez l’expérience.
+
+
Étape 4 : Formatage inline et bloc – les quatre méthodes
+
Notion offre quatre manières d’appliquer le formatage, que vous devez toutes reproduire pour une expérience identique.
+-
+
- Saisie Markdown WYSIWYG : Lorsque l’utilisateur tape
**texte**, l’éditeur capture les délimiteurs, les masque immédiatement et applique le style gras. La même logique vaut pour_italique_,`code`,~barré~. Pour le bloc,#,*,>,---transforment le type du bloc dès l’espace suivant.
+ - Raccourcis clavier :
Cmd/Ctrl+Bpour le gras,Ipour l’italique,Upour le souligné,Shift+Spour le barré,Epour le code inline,Kpour le lien. Les touches doivent fonctionner en mode édition inline et basculer l’état du style.
+ - Barre d’outils flottante : Elle apparaît automatiquement lors d’une sélection de texte, avec une animation de fondu et de glissement (200ms
ease-in-out). Elle contient des boutons pour le gras, l’italique, le lien, les couleurs, la mention, la date, et la transformation du bloc. Le bouton de couleur ouvre un sélecteur en grille des 10 familles de couleurs, à la fois pour le texte et le fond.
+ - Commande slash de couleur :
/turnouvre ce même sélecteur ;/defaultsupprime toutes les couleurs du bloc.
+
Implémentez cette double posture en maintenant une structure de marqueurs internes (offsets de début et de fin avec type de style) et en les rendant sous forme de balises <strong>, <em>, etc., lorsque le bloc est affiché. Cela permet l’export Markdown sans perte (Guide to Editing and Formatting Text).
+
Étape 5 : Glisser-déposer et gestion de l’arborescence
+Le drag-and-drop repose sur une poignée 6 points (⋮⋮) qui apparaît au survol d’un bloc avec une transition de fond rgba(55,53,47,0.08) en 100ms. L’icône est grise (#9B9A97) et devient plus foncée au survol. L’utilisateur peut :
-
+
- Déplacer verticalement un bloc en le faisant glisser. +
- Imbriquer : lors du drop, si la souris est décalée horizontalement vers la droite, le bloc devient enfant du bloc au-dessus. L’UI affiche une prévisualisation de l’indentation (ligne verticale
#E3E2E0) pendant le glissement.
+ - Déplacer plusieurs blocs : sélection multiple en faisant glisser sur les poignées ou avec
Shift+clic; les enfants sont entraînés automatiquement.
+
L’animation de drop est optimiste : l’état local de l’arbre est modifié immédiatement, puis la nouvelle position (index fractionnel) est synchronisée avec le serveur via l’algorithme CRDT. L’index fractionnel permet d’insérer un bloc entre deux blocs sans conflit, même en édition concurrente. Chaque bloc se voit attribuer un index de type chaîne généré par un compteur distribué ou un algorithme dédié (Frontend System Design).
+Les raccourcis clavier Tab et Shift+Tab modifient le niveau d’indentation de manière identique, en mettant à jour la relation parent-enfant et l’index.
+
Étape 6 : Design System visuel : les tokens CSS
+
Pour que l’interface soit indiscernable de Notion, vous devez reproduire rigoureusement son langage visuel. Implémentez les variables CSS suivantes (extraits des guidelines de conception) (Notion Design Tokens, Typography & CSS Variables ; notion.so · brand guidelines) :
+Couleurs
+- Primaire : #0075DE, accent #213183.
+- Échelle de gris : #FBFBFA (fond page), #FFFFFF (fond éditeur), #E3E2E0 (bordures légères), #9B9A97 (texte placeholder), #37352F (texte principal).
+- Palette vive (10 familles) pour le texte et le fond des blocs.
Typographie +- Police : NotionInter (ou Inter par défaut), 400, 500, 600, 700. +- Tailles : corps 16px/1.5, code 14px/1.4 JetBrains Mono, titres comme décrit plus haut.
+Espacement +- Unité de base 2px. Espacements clés : 20, 24, 32, 40, 48, 56, 60px. Indentation : 24px par niveau. Marges verticales entre blocs : 4px, avec 8px avant/après les titres.
+Rayons de bordure : 4px (blocs), 8px (popovers), 12px (modales), 16px (images).
+Ombres portées
+- sm: 0 2px 8px rgba(0,0,0,0.06)
+- md: 0 4px 16px rgba(0,0,0,0.08) (menu slash, barre flottante)
+- lg: 0 8px 32px rgba(0,0,0,0.12) (modales)
Animations : durée 100ms pour les hover, 200ms pour l’apparition des menus, courbe ease-in-out. Les états de focus utilisent un contour bleu de 2px.
+
Étape 7 : Blocs avancés – médias, bases de données et vues
+En plus des blocs de texte, Notion intègre un riche éventail de blocs de contenu (Types of content blocks) :
+-
+
- Image, Vidéo, Audio, Fichier : upload ou lien externe. Le rendu s’adapte à la largeur de la page, avec un rayon de 8px. +
- Signet web : carte d’aperçu enrichie (titre, description, favicon) générée lors du collage d’une URL. +
- Embeds : plus de 500 services (Figma, Google Maps, Tweet…) intégrés via iframe lorsque l’URL est collée directement. +
- Équation LaTeX : inline
$E=mc^2$ou bloc$$...$$, rendu avec KaTeX. Le rendu bascule du code source à la formule une fois le focus perdu.
+ - Bouton de modèle : génère une structure de blocs prédéfinie en un clic. +
Les bases de données sont des blocs complexes. Chaque base est une collection de pages (items) dotées de propriétés typées (Texte, Nombre, Sélection, Date, Formule, Relation…). Elles supportent cinq vues interchangeables : Table, Board (Kanban), Calendar, Gallery, List. Chaque vue possède ses propres filtres, tris, groupements et options de layout (Views, filters, sorts & groups). La vue Table, par exemple, doit permettre le gel de colonnes, le redimensionnement, et le tri par clic d’en-tête.
+Pour implémenter les bases de données, créez un sous-système de stockage propre avec un schéma flexible et une couche de rendu dédiée à chaque vue. La synchronisation des cellules s’appuie sur le même mécanisme CRDT que le texte.
+++Tip: Pour la coloration conditionnelle des propriétés de type Sélection, utilisez la couleur de l’étiquette définie par l’utilisateur (ex. « Urgent » en rouge).
+
+
Étape 8 : Collaboration temps réel et synchronisation
+
Le multi-utilisateur est au cœur de Notion. Chaque modification (frappe, déplacement, changement de style) doit être immédiatement visible par les autres. Votre architecture doit inclure :
+-
+
- CRDT de séquence pour le texte à l’intérieur de chaque bloc. Utilisez Yjs, qui fournit un type
Y.Textgérant automatiquement la fusion des éditions concurrentes.
+ - CRDT d’arbre pour la hiérarchie : les déplacements de blocs sont traités via des index fractionnels stockés dans une
Y.Map. Yjs supporte les structures arborescentes, mais vous pouvez aussi le faire manuellement avec des listes ordonnées et des index fractionnels répliqués.
+ - Curseurs distants : chaque collaborateur envoie sa position de curseur sous forme d’annotation (bloc cible + offset). Vous les affichez avec un chevron coloré portant le nom de la personne, intégré dans un calque au-dessus du texte. +
- Rendu optimiste : toute action locale est appliquée immédiatement dans l’état React, puis envoyée au serveur, qui la diffuse aux autres pairs. En cas de conflit, le CRDT assure la convergence finale sans blocage. +
La latence perçue est nulle et les conflits de formatage ou de déplacement sont résolus automatiquement. Pour minimiser la bande passante, ne synchronisez que les blocs modifiés et utilisez une connexion WebSocket persistante.
++
Étape 9 : Export et interopérabilité Markdown
+L’éditeur doit maintenir une double représentation : le texte brut avec marqueurs Markdown (pour l’export et la copie) et le contenu formaté affiché. Lors de l’export d’une page au format Markdown, régénérez les marqueurs à partir des styles internes (ex. **gras**). L’import Markdown suit le chemin inverse : parsez les marqueurs et créez l’arbre de blocs correspondant. Le moteur de parsing peut être le même que celui utilisé pour la saisie WYSIWYG.
+
Common Mistakes
+-
+
- Ignorer l’IME : ne pas tester la composition de caractères (japonais, chinois) conduit à des bugs où la touche « / » déclenche le menu slash pendant la saisie. +
- Utiliser
innerHTML: pour l’édition, manipuler directement le DOM brise le modèle de données et empêche le suivi des décorations. Préférez un éditeur contrôlé avec des offsets.
+ - Oublier la virtualisation : sans liste virtualisée, une page de 1000 blocs sera inutilisable. +
- Glisser-déposer non résilient : ne pas utiliser d’index fractionnel entraîne des conflits lors des déplacements concurrents. L’implémentation naïve avec des entiers oblige à réindexer toute la liste. +
- Ne pas respecter l’atomicité des blocs : si un lien embarqué est traité comme du texte inline, la carte d’aperçu ne sera pas générée. Chaque type de contenu doit être un bloc dédié avec ses propres handlers. +
- Design system incomplet : omettre les palettes de couleur ou les jetons d’espacement rend l’interface visuellement décalée. Reproduisez jusqu’aux ombres
xset aux transitions de 50ms.
+
Conclusion
+Reconstruire l’éditeur Notion à l’identique exige une maîtrise fine de l’architecture en blocs, de l’édition WYSIWYG, du design system et de la collaboration temps réel. Ce guide a détaillé chaque couche : du modèle de données à l’interface utilisateur, en passant par la commande slash, le glisser-déposer, les bases de données, et les tokens CSS. En appliquant rigoureusement ces spécifications – des index fractionnels aux animations de 200ms, des 10 familles de couleurs aux propriétés typées des bases – un développeur peut produire un clone fidèle, capable de servir des millions d’utilisateurs simultanés. Le code, l’état d’esprit et les détails visuels constituent un tout : seule une attention obsessionnelle à chaque interaction permet de capturer l’essence de Notion.
+Sources consultées : Thomas Frank’s Notion guides, Notion Help Center, DesignMD tokens, Frontend System Design interview, Dembrandt et Designlang.
+ +