Search

Ctrl + K

EmojiReaction

This document outlines the steps to create EmojiReaction component styled withTailwind CSS and using some npm dependency libraries.

Prerequisites

  • Node.js and npm installed on your machine.
  • Tailwind CSS installed in your project.
  • CVA(class-variance-authority) is a utility for managing CSS class names based on various conditions.
  • clsx is a tiny utility for constructing className strings conditionally.
Step 1: Create Tailwind configs
1// tailwind.config.js
2module.exports = {
3  ...
4  theme: {
5    ...
6    extend: {
7      ...
8      keyframes: {
9        "fly-emoji": {
10          "0%": {
11            transform: "translateY(0) scale(1)",
12            opacity: "0.7",
13          },
14          "100%": {
15            transform: "translateY(-150px) scale(2)",
16            opacity: "0",
17          },
18        },
19      },
20      animation: {
21        "fly-emoji": "fly-emoji 1s forwards",
22      },
23    },
24  },
25  plugins: [require("tailwindcss-animate")]
26};
27
Step 2: Create EmojiReaction component
1// emoji-reaction.component.tsx
2import clsx from "clsx";
3import { useEffect, useRef, useState } from "react";
4
5interface CurrentEmoji {
6  emoji: string;
7  id: number;
8}
9
10interface EmojiReactionProps {
11  emojis: string[];
12  disabled?: boolean;
13  className?: string;
14}
15
16const EmojiReaction: React.FC<EmojiReactionProps> = ({
17  emojis,
18  disabled,
19  className,
20}) => {
21  const [currentEmoji, setCurrentEmoji] = useState<CurrentEmoji | null>(null);
22
23  const clearEmojiTimeout = useRef<ReturnType<typeof setTimeout>>(null);
24
25  useEffect(() => {
26    const timeout = clearEmojiTimeout.current;
27
28    return () => {
29      if (timeout) clearTimeout(timeout);
30    };
31  }, []);
32
33  const handleEmojiClick = (emoji: string) => {
34    if (clearEmojiTimeout.current) clearTimeout(clearEmojiTimeout.current);
35
36    setCurrentEmoji({ emoji, id: Date.now() });
37
38    clearEmojiTimeout.current = setTimeout(() => {
39      setCurrentEmoji(null);
40    }, 3000);
41  };
42
43  return (
44    <div
45      className={clsx(
46        "mx-auto rounded-full border border-gray-300 bg-white dark:border-gray-700 dark:bg-gray-500",
47        className,
48      )}
49    >
50      <div className="grid items-center justify-start">
51        <div className="p-2">
52          <div className="grid grid-flow-col items-center justify-start">
53            {emojis.map((emoji) => (
54              <div key={emoji} className="relative w-fit">
55                <button
56                  className={clsx(
57                    "transition-bg-color duration-600 relative inline-flex items-center justify-center rounded-full bg-transparent p-1 align-middle text-2xl leading-6 ease-in-out active:duration-0",
58                    {
59                      "hover:bg-gray-200 active:bg-gray-400": !disabled,
60                    },
61                  )}
62                  disabled={disabled}
63                  onClick={() => handleEmojiClick(emoji)}
64                >
65                  {emoji}
66                  {currentEmoji && currentEmoji.emoji === emoji && (
67                    <span
68                      key={currentEmoji.id}
69                      className="animate-fly-emoji duration-3000 absolute -top-10 left-0 right-0 mx-auto"
70                    >
71                      {currentEmoji.emoji}
72                    </span>
73                  )}
74                </button>
75              </div>
76            ))}
77          </div>
78        </div>
79      </div>
80    </div>
81  );
82};
83
84export default EmojiReaction;
85