JSX logo

JSX en 10 points : ne plus confondre React et HTML

Lorsque l’on débute avec React ou Next.js, on entend très vite parler de JSX — cette syntaxe “HTML-like” qui semble familière… jusqu’à ce qu’elle ne le soit plus.

Pourquoi class devient className ? Pourquoi les if ne fonctionnent pas dans un return ? Et pourquoi faut-il écrire htmlFor au lieu de for ?
Autant de petites différences qui, cumulées, peuvent vite semer le doute chez les apprenants — ou casser un composant pour une raison invisible à l’œil non averti.

Dans cette fiche synthèse, je te propose un tour d’horizon des 10 différences clés à connaître pour bien écrire du JSX, comprendre les erreurs les plus fréquentes, et structurer ton code React avec clarté et confiance.

1. Ce qu’est JSX

JSX (JavaScript XML) est une extension de syntaxe pour JavaScript qui permet d’écrire du HTML dans du JavaScript. En réalité, ce n’est pas du HTML, mais une représentation déclarative de l’UI.

JSX est transpilé (généralement par Babel) en appels JavaScript classiques comme React.createElement().

Comment React fonctionne en coulisse

React.createElement() est bien utilisé en interne, même avec Next.js, mais tu ne le vois jamais. Next.js intègre déjà Babel et les transformations JSX, donc tu n’as jamais besoin d’écrire ou voir React.createElement() à la main.

Quand tu écris ce composant :

export default function Hello() {
  return <h1>Hello, React !</h1>;
}

Next.js passe le JSX dans Babel. Babel convertit çà en React.createElement(…). React utilise ensuite ces React Elements pour construire le Virtual DOM et React affiche le bon contenu dans le navigateur. Le Virtual DOM (ou DOM virtuel) est une copie légère de la page web que React utilise pour travailler plus vite et plus proprement.

JSX n’est pas juste une syntaxe agréable — il joue un rôle central dans la façon dont React pense et construit l’interface utilisateur.

Lisibilité

JSX ressemble beaucoup à du HTML, ce qui le rend très naturel à lire, surtout pour ceux qui viennent du web classique.
On comprend en un coup d’œil ce qui va s’afficher.

<h1>Bonjour {user.name}</h1>

Cohérence

Avec JSX, tu écris la structure (HTML) et la logique (JS) dans un même fichier, dans un seul composant.
Cela rend ton code plus modulaire et plus facile à maintenir

const Product = ({ price }) => <p>Prix : {price} €</p>;

Dynamisme

JSX permet d’insérer n’importe quelle expression JavaScript entre des {} dans le HTML.
Tu peux afficher une variable, un calcul, un texte conditionnel, etc.

<p>{isLoggedIn ? "Bienvenue !" : "Veuillez vous connecter"}</p>

Performances

JSX est compilé automatiquement (par Babel) en appels optimisés comme React.createElement(...), ce qui :

  • permet à React de construire un Virtual DOM
  • compare les changements efficacement
  • et met à jour uniquement les parties modifiées dans la page

Résultat : un site rapide, réactif, sans rechargement inutile.

En résumé

<h1>Hello</h1>        // JSX que tu écris
↓
React.createElement('h1', null, 'Hello') // JS compilé
↓
React Element (objet JS)
↓
Virtual DOM (copie de la page)
↓
Mise à jour du DOM réel (seulement si nécessaire)

2. Interpolation

Utilise des accolades {} pour insérer du JS dans du JSX :

<h1>Hello {user.name}</h1>

3. Conditions

Avec && (shortcut operator)

{isLoggedIn && <p>Bienvenue !</p>}

Avec opérateur ternaire ? :

{isAdmin ? <AdminPanel /> : <UserPanel />}

Exemple pour les classes conditionnelles

className={`btn ${isActive && "active"}`}

ou plus complet :

className={`btn ${isActive ? "active" : "inactive"}`}

4. Listes / Mapping : rendering de listes avec key

Ne pas oublier la clé

<ul>
  {items.map((item, i) => (
    <li key={i}>{item}</li>
  ))}
</ul>

5. Fragments

Un fragment sert à grouper plusieurs éléments JSX sans ajouter de balise inutile dans le DOM, comme une <div>.

<>
  <h1>Titre</h1>
  <p>Texte</p>
</>

Pourquoi c’est utile ?

Imaginons que vous vouliez retourner plusieurs balises depuis un composant :

return (
<h1>Titre</h1>
<p>Paragraphe</p>
);

Ici React ne peut pas retourner plusieurs éléments frères sans les encapsuler.

Solution 1 (classique, mais pas toujours idéale)

return (
  <div>
    <h1>Titre</h1>
    <p>Paragraphe</p>
  </div>
);

Une <div> inutile dans le DOM peut perturber le CSS, le layout, ou polluer le HTML.

return (
  <>
    <h1>Titre</h1>
    <p>Paragraphe</p>
  </>
);

Un layout dans Next.js est l’équivalent moderne d’un include en PHP, mais pensé pour les interfaces React et le rendu côté client ou côté serveur.

Si tu viens du monde PHP, pense au layout.jsx comme à un fichier maître qui contient tous tes include() (menu, pied de page, etc.), et dans lequel tu placeras un espace réservé {children} pour afficher le contenu dynamique de chaque page.

Voici l’exemple d’un RootLayout

// app/layout.jsx
export default function RootLayout({ children }) {
  return (
    <html lang="fr">
      <body>
        <header>
          <h1>Mon site</h1>
          <nav>
            <a href="/">Accueil</a> | <a href="/contact">Contact</a>
          </nav>
        </header>

        <main>
          {children} {/* Ici s'affiche le contenu des pages */}
        </main>

        <footer>
          <p>© 2025 - Mon site</p>
        </footer>
      </body>
    </html>
  );
}

6. Fonctions dans JSX

const formatPrice = (price) => `${price} €`;

<p>{formatPrice(19.99)}</p>

Ici la fonction est déclarée. Elle reçoit un nombre (comme 19.99) et retourne une chaîne formatée, ici "19.99 €".

Cette fonction est appelée dans JSX. React remplace {formatPrice(19.99)} par "19.99 €" dans le HTML final.

C’est pratique pour réutiliser du code sans le recopier partout, pour transformer / formater des données avant affichage, pour garder du JSX propre et lisible.

7. Classes dynamiques (avec clsx ou classnames)

npm install clsx
import clsx from "clsx";

const className = clsx("text-blue-500", {
  "font-bold": pathname === "/contact",
});

Contrairement à la méthode native, qui devient rapidement difficile à lire dès que plusieurs conditions s’enchaînent — avec un risque d’oubli d’espace ou de génération de valeurs comme undefined ou "false"clsx offre une syntaxe plus claire, tout en étant plus légère et rapide que l’ancienne bibliothèque classnames.

const className = `text-blue-500 ${pathname === "/contact" ? "font-bold" : ""}`;

Ancienne méthode

import classNames from "classnames";

const className = classNames("text-blue-500", {
  "font-bold": pathname === "/contact",
});

8. Entourer le JSX de parenthèses dans un return multi-ligne

En React, quand un composant est écrit avec return, il peut retourner une valeur unique (comme du JSX) mais si le JSX s’étale sur plusieurs lignes, il faut l’entourer de parenthèses pour que JavaScript le comprenne correctement.

Avec les parenthèses React comprend qu’il faut retourner tout ce bloc JSX.

return (
  <div>
    <h1>Hello</h1>
    <p>World</p>
  </div>
);

En JavaScript, si une instruction return est immédiatement suivie d’un saut de ligne, le moteur considère que la valeur retournée est vide (undefined) et ignore tout ce qui suit.

9. Conditions if

Dans JSX, tu ne peux pas écrire un if classique entre des accolades, car ce n’est pas une expression, mais une instruction. JSX n’accepte que des expressions à évaluer.

En JavaScript, une expression c’est du code qui renvoie une valeur.

2 + 3               // renvoie 5
"user" + "name"     // renvoie "username"
isLoggedIn && "Bienvenue"  // renvoie "Bienvenue" ou false

Une instruction c’est du code qui fait quelque chose, mais qui ne produit pas directement de valeur.

if (isLoggedIn) {
  console.log("Bienvenue");
}

for (let i = 0; i < 5; i++) {
  ...
}

En JSX seules les expressions sont autorisées entre les accolades

<p>{isLoggedIn && "Bienvenue"}</p>

Comme JSX n’accepte pas les instructions comme if, il est toujours possible de les utiliser à l’extérieur du return, ou avant le JSX, dans la fonction du composant.

Méthode 1 en préparant l’affichage avant le return :

function Message({ isLoggedIn }) {
  let content;

  if (isLoggedIn) {
    content = <p>Bienvenue !</p>;
  } else {
    content = <p>Connecte-toi.</p>;
  }

  return <div>{content}</div>;
}

Méthode 2 en utilisant une fonction ou logique en dehors du JSX

function UserGreeting({ user }) {
  if (!user) {
    return <p>Chargement...</p>; // instruction autorisée car c’est le return de la fonction
  }

  return (
    <div>
      <h1>Bonjour {user.name}</h1>
    </div>
  );
}

Méthode 3 : en transformant une instruction if en expression avec un ternaire

<p>{isLoggedIn ? "Bienvenue" : "Connecte-toi"}</p>

Tableau de transformation JSX

Situation (logique souhaitée)if interdit en JSXSolution avec expression
Afficher un contenu si une condition est vraie{if (cond) <p>Oui</p>} {cond && <p> Oui </p> }
Afficher l’un ou l’autre contenu selon une condition{ if (cond) <p>Oui</p> else <p>Non</p> }{ cond ? <p>Oui</p> : <p>Non</p> }
Plusieurs conditions imbriquéesif (a) {...} else if (b) {...} else {...}Utiliser if avant le return, ou un switch
Choisir dynamiquement une variable JSX à afficherif (cond) el = <A /> else el = <B />Définir la variable avant le return, puis {el}

10. class devient className=

En JavaScript, class est un mot-clé réservé. React utilise className à la place pour ne pas entrer en conflit avec le langage.

<div className="container"></div>

11. for= (dans une balise ) → devient htmlFor=

Là aussi, for est réservé en JavaScript (ex. : for (...) {}), donc JSX utilise htmlFor pour le champ de formulaire associé.

function ContactForm() {
  return (
    <form>
      <label htmlFor="email" className="block mb-2 font-semibold">
        Email
      </label>
      <input
        type="email"
        id="email"
        name="email"
        className="border px-3 py-2 rounded w-full"
        placeholder="Entrez votre email"
      />
    </form>
  );
}

export default ContactForm;

12. Bonus : composants clients vs serveurs ("use client")

Depuis Next.js 13, un fichier .jsx ou .tsx est par défaut un composant serveur.

Quand tu crées un composant React dans Next.js, il est par défaut exécuté côté serveur (donc sur l’ordinateur qui héberge ton site). C’est très pratique pour les performances. Mais il y a un petit souci.

Certains outils de React, appelés « hooks » (useState, useEffect, usePathname, etc.)
ne fonctionnent que dans le navigateur, donc côté client.

En React, un hook est un outil intégré qui te permet d’ajouter des fonctionnalités dynamiques dans un composant sans avoir besoin d’écrire une classe.

Les hooks sont comme des super-pouvoirs que tu donnes à tes composants pour réagir à des changements, gérer des données, ou interagir avec le navigateur.

Le hook useState : pour gérer une valeur qui change

C’est le hook le plus utilisé. Il sert à créer une variable « vivante » qui peut changer quand l’utilisateur interagit avec la page.

"use client";
import { useState } from "react";

export default function Compteur() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Tu as cliqué {count} fois</p>
      <button onClick={() => setCount(count + 1)}>Clique ici</button>
    </div>
  );
}

count est la valeur actuelle

setCount est la fonction qui permet de la modifier

useState(0) indique que la valeur de départ est 0

Le hook useEffect : pour réagir à des événements

Ce hook permet d’exécuter du code au bon moment (au chargement de la page, quand une donnée change, etc.).

"use client";
import { useEffect } from "react";

useEffect(() => {
  console.log("Composant affiché !");
}, []);

Ici, useEffect agit comme : “Fais ceci une fois au chargement de la page.”

Le hook usePathname (Next.js) : pour récupérer l’URL actuelle

C’est un hook spécifique à Next.js, utile quand tu veux connaître sur quelle page se trouve l’utilisateur.

"use client";
import { usePathname } from "next/navigation";

const pathname = usePathname(); // "/dashboard", "/blog", etc.

Pourquoi « use client » est obligatoire ?

Tous ces hooks ont besoin du navigateur pour fonctionner, car ils dépendent :

  • d’interactions utilisateur (click, input, etc.)
  • ou de l’environnement du navigateur (window, URL, localStorage, etc.)

Donc, tu dois déclarer tout en haut du fichier :

"use client";

Sans ça, Next.js croira que tu veux exécuter ton composant côté serveur, ce qui entraînera une erreur.

En conclusion

JSX n’est pas du HTML, et c’est justement ce qui le rend si puissant et structurant dans un projet React ou Next.js.
Mais pour en tirer pleinement parti, il est essentiel de bien comprendre ses particularités : expressions au lieu d’instructions, noms d’attributs adaptés, syntaxe déclarative et composition par composants.

Avec ces 10 points en tête, tu évites non seulement les erreurs les plus fréquentes, mais tu gagnes aussi en lisibilité, en maintenabilité… et en sérénité.

Que tu sois étudiant, développeur en reconversion ou formateur, cette fiche est conçue comme un repère de base, à consulter à chaque fois qu’un doute survient.
Et si tu veux aller plus loin, je t’invite à consulter mes autres ressources autour de React, Next.js et la pédagogie du développement web moderne.

Catégories : Architecture de l’information & Documentation numérique
Retour en haut