Difficulté : Avancé
Temps de développement estimé : 40 à 60 heures (selon le stack et les intégrations)
Prérequis techniques : React (ou framework moderne), gestion d’état (Redux/Zustand), CSS-in-JS ou SCSS, bibliothèque de drag & drop comme dnd-kit, connaissance des design tokens pour thèmes clair/foncé.
Ce guide vous donne toutes les clés pour reproduire à l’identique le menu de navigation gauche de Notion, en couvrant chaque composant visuel, chaque interaction utilisateur et chaque règle d’affichage conditionnelle. Il s’appuie directement sur la documentation officielle12 et les meilleures pratiques UX3 pour garantir une expérience fluide et fidèle.
Quick Guide (Raccourci pour développeurs)
- Créer un conteneur fixe de 240 px de large, 100 vh de hauteur, fond sombre.
- Ajouter l’en-tête du workspace (avatar + nom), avec un menu déroulant contextuel.
- Empiler les 5 onglets principaux : Home, Chat (si IA activée), Meetings (si plan payant), Inbox (avec badge), Search (déclenche Quick Find).
- Structurer les sections repliables titrées : Recents, Favorites (drag & drop autorisé), Agents, Shared (avec sous-niveaux Teamspaces), Private, Notion apps.
- Placer les liens utilitaires fixes (My Tasks, Library, Marketplace, Help, Trash) au-dessus du pied.
- Ajouter un pied sticky contenant le bouton “+ New” (ouvre un menu de création) et “New Chat” (si IA).
- Gérer la réduction de la sidebar à 56 px (mode icônes seules) via un hamburger, avec infobulles au survol.
- Conditionner l’affichage des onglets Chat, Meetings, Agents et New Chat selon les droits utilisateur.
- Implémenter le drag & drop uniquement sur la section Favorites, avec persistance immédiate.
- Sauvegarder localement les préférences (sections dépliées, ordre des favoris, mode réduit).
- Appliquer les design tokens pour supporter les thèmes clair et foncé.
Prérequis
Avant de commencer, assurez-vous de maîtriser les concepts suivants :
- React et le state management : la sidebar est un composant racine qui consomme des données dynamiques (pages, notifications, profil utilisateur).
- Design responsive et accessibilité : bien que le guide se concentre sur la version desktop, une adaption mobile (off‑canvas) est nécessaire ; nous aborderons le mode réduit mais pas le responsive mobile en détail.
- Notion API ou faux backend : pour les tests, vous aurez besoin d’une source de données modélisant les pages, les teamspaces et les permissions.
- Compréhension des conditions Notion : l’affichage de Chat, New Chat, Meetings et Agents dépend du plan et de l’activation de l’IA. Référez-vous à la documentation2 pour le mapping exact des droits.
Step 1: Mise en place du conteneur et du style de base
Spécifications UI
Le panneau latéral est un élément aside (ou nav) avec les propriétés suivantes :
.sidebar {
width: 240px;
min-width: 240px;
height: 100vh;
position: fixed;
left: 0;
top: 0;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
background-color: var(--sidebar-bg);
color: var(--sidebar-text);
border-right: 1px solid var(--border-color);
box-shadow: 0 0 8px rgba(0,0,0,0.05);
transition: width 0.25s ease, min-width 0.25s ease;
}
.sidebar.collapsed {
width: 56px;
min-width: 56px;
}
Utilisez des variables CSS pour les couleurs afin d’assurer la compatibilité avec un thème sombre/clair. Par exemple :
- --sidebar-bg: #f7f6f3; (clair), --sidebar-bg: #191919; (sombre)
- --sidebar-text: #37352f; (clair), --sidebar-text: #d3d3d3; (sombre)
- --accent: #2383e2;
La hauteur pleine écran est gérée par height: 100vh. Le défilement vertical interne permet aux très longs contenus de rester accessibles.
Tip: Pour éviter un double défilement avec le contenu principal, appliquez
overflow: hiddensurbodylorsque la sidebar est en mode off‑canvas sur mobile.
Step 2: En-tête du workspace
Composant WorkspaceHeader
Affichez un avatar rond (32×32 px) et le nom du workspace. Le nom est tronqué avec text-overflow: ellipsis si nécessaire.
<button className="workspace-header" onClick={toggleMenu}>
<img src={workspace.icon} alt="" className="workspace-avatar" />
<span className="workspace-name">{workspace.name}</span>
<ChevronDownIcon />
</button>
L’interaction : - Un clic ouvre un panneau contextuel aligné sous l’en-tête, affichant : “Changer de workspace”, “Paramètres du workspace”, “Notifications”, etc. - Le menu se ferme au clic extérieur ou sur un élément.
UX : cet en-tête ancre l’identité du workspace courant et donne un accès rapide aux réglages globaux.
Warning: Ne pas utiliser
position: absolutepour le menu flottant sans avoir un conteneur parentposition: relative. Une alternative est d’utiliser un portal React pour éviter les débordements de la sidebar.
Step 3: Onglets de navigation primaires
Cinq éléments empilés verticalement, chacun composé d’une icône (16 px) et d’un libellé (font-size 14 px, graisse normale). L’onglet actif reçoit un fond légèrement plus clair et une barre verticale gauche de 3 px.
Structure d’un onglet :
<NavItem
icon={<HomeIcon />}
label="Home"
to="/home"
active={currentRoute === '/home'}
/>
Comportements spécifiques :
| Onglet | Icône | Rendu conditionnel | Action |
|---|---|---|---|
| Home | 🏠 | Toujours affiché | Navigation vers /home |
| Chat | 💬 | userPlan.aiEnabled === true |
Navigation vers l’interface IA, affiche éventuellement un indicateur de conversation active |
| Meetings | 📅 | userPlan.includesMeetings === true |
Filtre les pages avec blocs de type réunion |
| Inbox | 🔔 | Toujours affiché | Ouvre une modale latérale listant les notifications ; badge non‑lu mis à jour en temps réel |
| Search | 🔍 | Toujours affiché | Déclenche Cmd/Ctrl+K en appelant la fonction openQuickFind() |
Détail de l’Inbox :
- La propriété unreadCount est récupérée via polling ou WebSocket.
- Le badge est un petit cercle rouge avec le nombre, affiché seulement si unreadCount > 0.
- Au clic, une modale s’ouvre. L’utilisateur peut marquer tout comme lu, ce qui réinitialise le badge.
Tip: Pour reproduire exactement le comportement Notion, le clic sur Search ne navigue pas mais active une modale superposée avec un champ de saisie autofocusé. Implémentez
QuickFindModalindépendamment.
Step 4: Sections de pages repliables

Chaque section est un composant générique SidebarSection avec :
- un en-tête cliquable (chevron animé + titre en majuscules 12 px, lettre-spacing 0.5 px) ;
- une liste d’items SidebarItem.
L’ordre des sections est imposé : Recents, Favorites, Agents, Shared, Private, Notion apps. Elles sont empilées dans l’ordre vertical.
4.1 Section Recents
- Générée automatiquement, tri antéchronologique.
- Pas d’interaction manuelle (pas de suppression ni de drag).
- Se met à jour immédiatement quand une page est consultée.
4.2 Section Favorites
- L’utilisateur épingle une page via le menu “Add to Favorites”.
- Chaque item est draggable ; toute la ligne est déplaçable (poignée invisible).
- Ordre sauvegardé immédiatement après
drop. - Survol : un bouton “…” apparaît pour un menu contextuel (Retirer des favoris, Copier le lien, etc.).
Implémentation du drag & drop :
<DndContext onDragEnd={handleDragEnd}>
<SortableContext items={favorites}>
{favorites.map(page => (
<SortableItem key={page.id} id={page.id}>
<SidebarItem page={page} />
</SortableItem>
))}
</SortableContext>
</DndContext>
Warning: Seule la section Favorites doit accepter le réordonnancement. Toute autre tentative de glisser un élément doit être ignorée pour coller au comportement original.
4.3 Section Agents
- Affichage conditionnel : section masquée si aucun agent IA n’est configuré.
- Chaque agent est un lien vers une conversation ou un contexte dédié.
4.4 Section Shared
- Regroupe les pages partagées et les Teamspaces.
- Possibilité d’un sous‑niveau par Teamspace : l’en-tête de teamspace est en gras, avec une icône d’équipe et un chevron pour replier ses pages.
- Des badges “Nouveau” peuvent apparaître sur les pages récemment mises à jour.
- L’ordre des Teamspaces et des pages n’est pas modifiable librement par l’utilisateur final (il est défini par les administrateurs).
Modèle de données :
interface SharedSection {
teamspaces: Array<{
id: string;
name: string;
pages: Page[];
collapsed: boolean;
}>;
directSharedPages: Page[];
}
4.5 Section Private
- Pages personnelles non partagées.
- Aucun badge de partage ; seule l’icône standard.
4.6 Section Notion apps
- Intégrations tierces (Jira, Figma, etc.).
- Masquée si aucune application n’est connectée.
Comportements communs :
- Survol : fond plus clair var(--hover-bg), curseur pointer.
- Clic : navigue vers la page ; l’élément prend l’état actif (surlignage).
- Clic droit : menu contextuel natif (Ouvrir dans un nouvel onglet, Dupliquer, etc.).
- Réduction/extension : le chevron pivote de 90° à l’état replié avec une transition transform 0.2s ease. L’état est sauvegardé localement par utilisateur.
Tip: Stockez l’état
collapsedde chaque section dans un objetuserPreferences.sectionsState. UtilisezlocalStoragepour une persistance instantanée, tout en synchronisant de temps en temps avec le backend.
Step 5: Liens utilitaires
Une série de boutons simples, sans chevron ni sous-section, placés dans une div séparée au-dessus du pied.
Liste fixe dans l’ordre : 1. My Tasks 2. Library 3. Marketplace 4. Help 5. Trash
Ces liens ne supportent ni le drag, ni le réordonnancement. Leur comportement est un simple history.push ou window.location. La corbeille (Trash) pointe vers une page dédiée. L’icône de chaque lien est une illustration spécifique (fournie par le set d’icônes Notion).
Step 6: Pied d’actions rapides

Deux boutons always‑visible en bas de la barre, positionnés en sticky :
.sidebar-footer {
position: sticky;
bottom: 0;
background: var(--sidebar-bg);
padding: 12px 16px;
border-top: 1px solid var(--border-color);
margin-top: auto;
}
Bouton “+ New” :
- Bouton principal, largeur pleine, couleur d’accentuation var(--accent).
- Icône “+” à gauche.
- onClick → ouvre un menu flottant (portal) proposant : Page, Base de données, Calendrier, Import, etc.
- La sélection déclenche la création et l’ouverture de l’élément.
- Le menu se ferme au clic extérieur ou après sélection.
Bouton “New Chat” :
- Bouton secondaire avec une icône de bulle.
- Visible uniquement si userPlan.aiEnabled === true2.
- onClick → bascule l’onglet Chat et démarre une nouvelle conversation IA.
Tip: Associez un raccourci clavier
Cmd/Ctrl + Npour l’action “+ New” et affichez le raccourci dans une infobulle au survol.
Step 7: Interactions avancées et dynamiques
Mode réduit (icônes seules)
Un bouton hamburger (ou un raccourci Cmd/Ctrl + \) réduit la sidebar à 56 px. Pendant la transition, les libellés disparaissent en fondu (opacity: 0). Les sections deviennent inaccessibles directement ; au survol d’une icône, un tooltip affiche le nom complet, et un clic sur une section ouvre un popover listant ses items.
<button onClick={toggleCollapsed} className="collapse-btn">
<HamburgerIcon />
</button>
Recherche unifiée (Quick Find)
Le composant QuickFindModal s’affiche en overlay, centré, avec un champ de saisie autofocusé. La frappe filtre en temps réel les résultats (pages, bases de données, commentaires). Implémentez un système de recherche côté client pour la vitesse.
Badge Inbox en temps réel
Abonnez-vous à un flux de notifications (WebSocket) ou faites du polling toutes les 30 secondes. Mettez à jour l’état global unreadCount ; le badge se met à jour réactivement.
Drag & drop dans les Favorites (rappel)
Utilisez exclusivement dnd-kit et les événements onDragEnd pour sauvegarder le nouvel ordre via l’API Notion ou un store local immédiat.
Step 8: Affichage conditionnel selon le plan utilisateur

Pour respecter les capacités du compte, créez un hook useUserPermissions() qui retourne :
{
planType: 'free' | 'plus' | 'business' | 'enterprise';
aiEnabled: boolean;
meetingsEnabled: boolean;
agentsActive: boolean;
}
Appliquez ces conditions dans le rendu :
- Onglet Chat → aiEnabled
- Onglet Meetings → planType !== 'free'
- Section Agents → agentsActive
- Bouton New Chat → aiEnabled
Si une condition n’est pas remplie, le composant correspondant n’est pas rendu (pas simplement masqué en CSS, pour éviter les trous dans la mise en page).
Warning: Ne jamais se baser uniquement sur le cache local pour ces permissions ; vérifiez-les au chargement et après chaque changement de plan.
Step 9: Accessibilité et responsive design
Respectez les critères WCAG AA :
- Tous les items sont focusables (tabIndex), l’ordre de tabulation suit l’ordre visuel.
- Rôles ARIA : navigation sur le conteneur, list et listitem sur les sections, button pour les actions.
- En mode réduit, utilisez l’attribut aria-label sur les icônes et des tooltips pilotés par aria-describedby.
- Contraste suffisant entre le texte et le fond dans les deux thèmes.
Pour le responsive (écrans < 768 px), remplacez la sidebar fixe par un bouton hamburger qui déclenche un tiroir off‑canvas coulissant depuis la gauche. L’implémentation de cette version mobile sort du cadre de ce guide centré sur la reproduction exacte de la sidebar desktop, mais prévoyez une architecture qui facilite ce basculement.
Step 10: Test et validation UX

Testez les scénarios suivants pour garantir la conformité avec Notion :
- Navigation fluide entre les onglets et les sections.
- Ajout/suppression d’un favori et réordonnancement persistant.
- Réduction/expansion de la sidebar et affichage des tooltips.
- Badge de notifications réactif et remise à zéro.
- Rendu conditionnel : connectez-vous avec un compte free, un compte plus sans IA, puis avec IA activée, et vérifiez que les composants appropriés apparaissent/disparaissent.
- Raccourcis clavier :
Cmd/Ctrl+Kdoit ouvrir Quick Find,Cmd/Ctrl+\doit réduire/étendre la sidebar. - Accessibilité : testez au lecteur d’écran la navigation complète.
Erreurs courantes
- Oublier de conditionner l’affichage des onglets Meetings et Chat → les utilisateurs sur plan gratuit verront des onglets inactifs ou manquants, ce qui nuit à l’expérience.
- Permettre le drag sur d’autres sections que Favorites → le comportement n’est pas authentique et peut provoquer des suppressions accidentelles.
- Ne pas persister l’état des sections pliées/dépliées → à chaque rechargement, l’utilisateur devra tout réorganiser, ce qui frustre.
- Ne pas animer la rotation du chevron ou la réduction de la sidebar → l’absence de transition donne une impression de bug.
- Stocker l’ordre des favoris uniquement en local sans le synchro serveur → en cas de changement d’appareil, les favoris seront perdus. Implémentez une sauvegarde côté backend via l’API Notion.
- Mettre le bouton Search sous forme de champ texte dans la sidebar → Notion utilise un bouton déclenchant une modale, ce qui économise l’espace et garde l’interface propre.
- Utiliser des tailles de police ou des espacements différents → respectez scrupuleusement les 14 px pour les libellés, 12 px pour les titres de section, et les marges internes de 8-12 px pour une reproduction fidèle.
- Négliger la gestion du thème → sans variables CSS, le basculement clair/foncé cassera l’apparence. Prévoir dès le départ les deux jeux de couleurs.
Conclusion

Ce guide vous a fourni l’ensemble des spécifications UI, des modèles d’interaction et des conditions métier nécessaires pour reproduire la barre de navigation gauche de Notion. En suivant les étapes détaillées, vous disposerez d’une sidebar réactive, personnalisée et fidèle à l’original, capable de s’adapter au plan de l’utilisateur et à ses préférences. La clé du succès réside dans une attention méticuleuse aux détails : chaque pixel, chaque transition et chaque condition d’affichage compte pour offrir une expérience utilisateur identique à celle que des millions d’utilisateurs connaissent.
Sources utilisées :
-
Notion Help Center – “Navigate with the sidebar” : [https://www.notion.com/help/navigate-with-the-sidebar](https://www.notion.com/help/navigate-with-the-sidebar ↩
-
Notion Help Center – “Sidebar navigation” : [https://www.notion.com/help/category/sidebar-navigation](https://www.notion.com/help/category/sidebar-navigation ↩↩↩
-
UX Planet – “Best UX Practices for Designing a Sidebar” : [https://uxplanet.org/best-ux-practices-for-designing-a-sidebar-9174ee0ecaa2](https://uxplanet.org/best-ux-practices-for-designing-a-sidebar-9174ee0ecaa2 ↩
