Guides
Adding Exit Animations

Adding Exit Animations

The <MagicExit> component is used to animate the removal of components from the DOM.

  • To animate the an element leaving add the exit property to the <MagicExit> tag.

Example: To Do List with Exit Animations on Delete

  • πŸ• Walk the dog
  • πŸ” Eat lunch
  • πŸ“š Study react
  • πŸ€ Play basketball
  • πŸ”Ž Study biology
  • πŸ‘Ÿ Buy shoes

Sample Code

To Do List With Exit Animations
import { type Dispatch, type SetStateAction, useRef, useState } from "react";
import { MagicMotion, MagicExit } from "react-magic-motion";
 
function shuffle<T>(array: T[]): T[] {
  let currentIndex = array.length;
  let randomIndex: number;
  let temporaryValue: T;
 
  // While there remain elements to shuffle
  while (currentIndex !== 0) {
    // Pick a remaining element
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;
 
    // And swap it with the current element
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }
 
  return array;
}
 
function TodoListItem({
  todo,
  setTodos,
}: {
  todo: {
    id: `${string}-${string}-${string}-${string}-${string}`;
    text: string;
  };
  setTodos: Dispatch<
    SetStateAction<
      {
        id: `${string}-${string}-${string}-${string}-${string}`;
        text: string;
      }[]
    >
  >;
}): JSX.Element {
  return (
    <li
      style={{
        display: "flex",
        justifyContent: "space-between",
        lineHeight: "2rem",
        padding: "0.35rem 1rem",
        backgroundColor: "rgb(239 239 239 / 70%)",
      }}
    >
      {todo.text}
      <button
        type="button"
        title="Delete this item"
        onClick={() =>
          setTodos((todos) => todos.filter((t) => t.id !== todo.id))
        }
      >
        πŸ—‘οΈ
      </button>
    </li>
  );
}
 
export default function TodoList(): JSX.Element {
  const [todos, setTodos] = useState([
    { id: crypto.randomUUID(), text: "πŸ• Walk the dog" },
    { id: crypto.randomUUID(), text: "πŸ” Eat lunch" },
    { id: crypto.randomUUID(), text: "πŸ“š Study react" },
    { id: crypto.randomUUID(), text: "πŸ€ Play basketball" },
    { id: crypto.randomUUID(), text: "πŸ”Ž Study biology" },
    { id: crypto.randomUUID(), text: "πŸ‘Ÿ Buy shoes" },
  ]);
 
  const newTodoInput = useRef<HTMLInputElement>(null);
 
  return (
    <MagicMotion>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: "1.5rem",
          marginTop: "1rem",
        }}
      >
        <ul
          style={{
            display: "flex",
            flexDirection: "column",
            gap: "0.75rem",
            overflow: "hidden",
          }}
        >
         <MagicExit exit={{ opacity: 0 }}>
           {todos.map((todo) => (
             <TodoListItem key={todo.id} todo={todo} setTodos={setTodos} />
           ))}
        </MagicExit>
        </ul>
        <form
          onSubmit={(e) => e.preventDefault()}
          style={{ display: "flex", gap: "1rem" }}
        >
          <input
            ref={newTodoInput}
            type="text"
            placeholder="Write a new todo πŸ“"
            style={{
              padding: "0.5rem 1rem",
              border: "none",
              borderRadius: "0.25rem",
              width: "100%",
              backgroundColor: "rgb(239 239 239)",
            }}
          />
 
          <button
            type="submit"
            title="Add a new todo"
            style={{
              whiteSpace: "nowrap",
              padding: "0.5rem 1rem",
              backgroundColor: "#5a70ed",
              color: "#ffffff",
            }}
            onClick={() => {
              if (!newTodoInput.current?.value) return;
              setTodos([
                ...todos,
                {
                  id: crypto.randomUUID(),
                  text: newTodoInput.current.value,
                },
              ]);
              newTodoInput.current.value = "";
            }}
          >
            Add Todo
          </button>
 
          <button
            type="submit"
            title="Shuffle Items"
            style={{
              whiteSpace: "nowrap",
              padding: "0.5rem 1rem",
              backgroundColor: "#eac530",
              color: "#ffffff",
            }}
            onClick={() => setTodos(shuffle([...todos]))}
          >
            πŸ”€
          </button>
        </form>
      </div>
    </MagicMotion>
  );
}