AccueilServicesPortfolioArticles
Contact
Créer une animation de liste UL avec Framer Motion sur React et Next.js

Créer une animation de liste UL avec Framer Motion sur React et Next.js

TutorielsReactFramer

Dans ce tutoriel, je vous montre comment créer une liste d'éléments animés en utilisant Framer Motion, une bibliothèque que j'utilise régulièrement dans mes projets pour ajouter des interactions et animations fluides. Ce code est conçu pour Next.js, mais je vous explique les quelques modifications nécessaires pour le rendre compatible avec React.

Étape 1 : Importer les dépendances

Framer Motion vous permet d'animer vos composants en quelques lignes. Commencez par installer Framer Motion si ce n’est pas déjà fait :

npm install framer-motion

Ensuite, importez les composants nécessaires au début de votre fichier.

"use client"; // Utilisé pour Next.js
import React, { useState } from "react";
import { AnimatePresence, LayoutGroup, motion } from "framer-motion";
import Image from "next/image"; // Utilisé pour Next.js.

Étape 2 : Configurer la liste d’éléments

Créez une liste d’objets pour représenter les éléments de votre liste. Ici, chaque élément a un id, un name, une description, et une descriptionLarge.

const elementsList = [
  {
    id: 1,
    name: "Élément 1",
    description: "Cliquez pour voir plus.",
    descriptionLarge: "Description détaillée de l'élément 1...",
  },
  {
    id: 2,
    name: "Élément 2",
    description: "Cliquez pour voir plus.",
    descriptionLarge: "Description détaillée de l'élément 2...",
  },
  {
    id: 3,
    name: "Élément 3",
    description: "Cliquez pour voir plus.",
    descriptionLarge: "Description détaillée de l'élément 3...",
  },
];

Étape 3 : Gérer l'état de l'élément sélectionné

Pour gérer l'affichage de la description détaillée d’un élément, créez un useState pour stocker l'élément sélectionné :

const [selectedId, setSelectedId] = useState(null);

Étape 4 : Afficher et Animer la Liste

Créez une liste <ul> qui contiendra chaque élément <li>. On utilise motion.li pour animer chaque élément lors du survol.

<motion.ul className="flex items-center gap-4">
  <LayoutGroup>
    {elementsList.map((element, index) => (
      <motion.li
        key={index}
        onClick={() => setSelectedId(element.id)}
        layoutId={element.id}
        whileHover={{ scale: 1.06 }}
        className="flex cursor-pointer flex-col gap-2 rounded border bg-gray-200 p-4 shadow-md"
      >
        <div className="flex h-20 w-full items-center justify-center rounded bg-gray-400">
          <Image src={"/image.svg"} width={30} height={30} alt="Image" />
        </div>
        <h2 className="text-base font-bold">{element.name}</h2>
        <p>{element.description}</p>
      </motion.li>
    ))}
  </LayoutGroup>
</motion.ul>

Explications

  • layoutId={element.id} : assure que chaque élément ait une transition fluide lors du changement d’état.
  • whileHover={{ scale: 1.06 }} : agrandit légèrement l’élément au survol.
  • <LayoutGroup> : garde la mise en page synchronisée et permet des animations cohérentes.

Étape 5 : Afficher les détails de l'élément sélectionné

Lorsqu'un élément est cliqué, on utilise AnimatePresence pour gérer l’affichage de la carte détaillée en superposition.

<AnimatePresence>
  {selectedId && (
    <div
      className="fixed left-0 top-0 z-50 flex h-full w-full items-center justify-center bg-black bg-opacity-30"
      onClick={() => setSelectedId(null)}
    >
      <motion.div
        layoutId={selectedId}
        className="flex w-11/12 max-w-lg flex-col gap-4 rounded-lg bg-gray-200 p-6 shadow-lg"
        animate={{ opacity: 1 }}
        transition={{ duration: 0.6, type: "spring" }}
      >
        <div className="flex h-36 items-center justify-center bg-gray-400">
          <Image src={"/image.svg"} width={30} height={30} alt="Image" />
        </div>
        <h2 className="text-xl font-bold">
          {elementsList[selectedId - 1].name}
        </h2>
        <p className="text-gray-700">
          {elementsList[selectedId - 1].descriptionLarge}
        </p>
      </motion.div>
    </div>
  )}
</AnimatePresence>

Explications

  • AnimatePresence : permet de gérer l’entrée et la sortie animée des composants.
  • layoutId={selectedId} : synchronise l’animation entre la vue réduite de l’élément et la vue détaillée.
  • onClick={() => setSelectedId(null)} : ferme la carte en cliquant sur l’arrière-plan.

Code Complet

Voici le code complet de l’animation de liste avec Framer Motion :

"use client";
import React, { useState } from "react";
import { AnimatePresence, LayoutGroup, motion } from "framer-motion";
import Image from "next/image";

const FramerList = () => {
  const elementsList = [
    {
      id: 1,
      name: "Élément 1",
      description: "Cliquez pour voir plus.",
      descriptionLarge: "Description détaillée de l'élément 1...",
    },
    {
      id: 2,
      name: "Élément 2",
      description: "Cliquez pour voir plus.",
      descriptionLarge: "Description détaillée de l'élément 2...",
    },
    {
      id: 3,
      name: "Élément 3",
      description: "Cliquez pour voir plus.",
      descriptionLarge: "Description détaillée de l'élément 3...",
    },
  ];

  const [selectedId, setSelectedId] = useState(null);

  return (
    <div className="flex flex-col gap-6">
      <motion.ul className="flex items-center gap-4">
        <LayoutGroup>
          {elementsList.map((element, index) => (
            <motion.li
              key={index}
              onClick={() => setSelectedId(element.id)}
              layoutId={element.id}
              whileHover={{ scale: 1.06 }}
              className="flex cursor-pointer flex-col gap-2 rounded border bg-gray-200 p-4 shadow-md"
            >
              <div className="flex h-20 w-full items-center justify-center rounded bg-gray-400">
                <Image src={"/image.svg"} width={30} height={30} alt="Image" />
              </div>
              <h2 className="text-base font-bold">{element.name}</h2>
              <p>{element.description}</p>
            </motion.li>
          ))}
          <AnimatePresence>
            {selectedId && (
              <div
                className="fixed left-0 top-0 z-50 flex h-full w-full items-center justify-center bg-black bg-opacity-30"
                onClick={() => setSelectedId(null)}
              >
                <motion.div
                  layoutId={selectedId}
                  className="flex w-11/12 max-w-lg flex-col gap-4 rounded-lg bg-gray-200 p-6 shadow-lg"
                  animate={{ opacity: 1 }}
                  transition={{ duration: 0.6, type: "spring" }}
                >
                  <div className="flex h-36 items-center justify-center bg-gray-400">
                    <Image src={"/image.svg"} width={30} height={30} alt="Image" />
                  </div>
                  <h2 className="text-xl font-bold">
                    {elementsList[selectedId - 1].name}
                  </h2>
                  <p className="text-gray-700">
                    {elementsList[selectedId - 1].descriptionLarge}
                  </p>
                </motion.div>
              </div>
            )}
          </AnimatePresence>
        </LayoutGroup>
      </motion.ul>
    </div>
  );
};

export default FramerList;

Conclusion

En quelques étapes, vous avez une liste interactive et animée avec Framer Motion et Next.js ! Ce tutoriel vous montre comment intégrer des animations facilement. Pour ceux utilisant React, remplacez simplement le composant Image de Next.js par une balise <img>. Amusez-vous à adapter le code à vos projets, et explorez la documentation de Framer Motion pour découvrir plus d’options d’animation.

Alexis Pennel

Alexis Pennel

Publié le 18 décembre 2024

Retour aux articles

Autres posts qui pourraient vous plaire

  • Composant de cartes avec skeleton loader en React.js et Tailwind CSS

    Composant de cartes avec skeleton loader en React.js et Tailwind CSS

  • Barre de recherche avec React et Framer Motion

    Barre de recherche avec React et Framer Motion

  • Créer un Header Responsive avec Menu Burger en Framer Motion

    Créer un Header Responsive avec Menu Burger en Framer Motion

  • Créez des Animations Fluides avec Framer Motion en React

    Créez des Animations Fluides avec Framer Motion en React

Un projet en tête ? Obtenez un devis gratuit.

Posez-moi vos questions ou décrivez votre projet web pour recevoir un devis gratuit, sans engagement, sous 48 heures.

Photo de Alexis Pennel, développeur web freelance
Alexis Pennel
Bonjour, moi, c'est Alexis ! Vous avez des questions sur mes services ou un projet en tête ? Décrivez-le en quelques mots pour recevoir un devis gratuit, poser vos questions, ou réserver un entretien !

Ou contactez-moi directement par email ou WhatsApp.