Docs
Terminal Text Hover Effect

Terminal Text Hover Effect

Hover Animations on Terminal-like Typography.

Tip

This component is best viewed on desktop.

Hover on the text

Valorant Agents

D
u
e
l
i
s
t
s
 
-
 
R
a
z
e
 
J
e
t
t
 
R
e
y
n
a
 
N
e
o
n
 
Y
o
r
u
 
P
h
o
e
n
i
x
 
I
s
o
I
n
i
t
i
a
t
o
r
s
 
-
 
G
e
k
k
o
 
S
o
v
a
 
K
a
y
o
 
F
a
d
e
 
B
r
e
a
c
h
 
S
k
y
e
C
o
n
t
r
o
l
l
e
r
s
 
-
 
O
m
e
n
 
C
l
o
v
e
 
V
i
p
e
r
 
H
a
r
b
o
r
 
A
s
t
r
a
 
B
r
i
m
S
e
n
t
i
n
e
l
s
 
-
 
C
y
p
h
e
r
 
K
i
l
l
j
o
y
 
C
h
a
m
b
e
r
 
S
a
g
e
 
D
e
a
d
l
o
c
k
 
V
y
s
e

Installation

Install the following dependencies:

npm
npm install framer-motion

Copy and paste the following code into your project.

components/ui/terminal-text-hover-effect.tsx
"use client";
 
import React, { useState, useRef, useEffect } from "react";
import { animate, motion, useAnimation, AnimationControls } from "framer-motion";
import { cn } from "@/lib/utils";
 
const lettersAndSymbols = [
  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
  "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "!", "@", "#", "$",
  "%", "^", "&", "*", "-", "_", "+", "=", ";", ":", "<", ">", ","
];
 
interface TerminalCharProps {
  char: string;
  delay: number;
  trigger?: boolean;
}
 
interface TerminalTextProps {
  trigger: boolean;
  children: string;
}
 
interface TerminalTextHoverEffectProps {
  children: string;
  className?: string;
}
 
const TerminalChar: React.FC<TerminalCharProps> = ({ char, delay, trigger }) => {
  const controls: AnimationControls = useAnimation();
  const originalChar = useRef<string>(char);
  const charRef = useRef<HTMLDivElement>(null);
  const [currentChar, setCurrentChar] = useState<string>(char);
  const [blockOpacity, setBlockOpacity] = useState<number>(0);
  const [timeoutID, setTimeoutID] = useState<NodeJS.Timeout | undefined>();
 
  const animation = async (): Promise<void> => {
    await controls.start({
      opacity: [0, 1],
      transition: { duration: 0.1 },
    });
    for (let i = 0; i < 3; i++) {
      setCurrentChar(
        lettersAndSymbols[Math.floor(Math.random() * lettersAndSymbols.length)]
      );
      if (i === 0) {
        setBlockOpacity(0);
      }
      await new Promise((resolve) => setTimeout(resolve, 40));
    }
    setCurrentChar(originalChar.current);
  };
 
  useEffect(() => {
    if (trigger) {
      clearTimeout(timeoutID);
      if (charRef.current) {
        animate(charRef.current, { opacity: 0 });
      }
      setTimeoutID(setTimeout(() => animation(), delay * 1000));
    }
  }, [trigger, delay]);
 
  return (
    <motion.div
      animate={controls}
      onAnimationStart={() => setBlockOpacity(1)}
      ref={charRef}
      className={`
        inline-block leading-[0.9] uppercase relative after:content-['']
        after:w-[1ch] after:absolute after:top-0 after:left-0
        after:bg-foreground after:h-full ${
          blockOpacity === 0 ? "after:opacity-0" : "after:opacity-1"
        }`}
    >
      {currentChar}
    </motion.div>
  );
};
 
const TerminalText: React.FC<TerminalTextProps> = ({ trigger, children }) => {
  return (
    <span className="hover-effect cursor-pointer group">
      {Array.from(children).map((char, index) => (
        char === " " ? (
          <div key={index} className="inline-block">{"\u00A0"}</div>
        ) : (
          <TerminalChar
            key={index}
            char={char}
            delay={index * 0.07}
            trigger={trigger}
          />
        )
      ))}
    </span>
  );
};
 
const TerminalTextHoverEffect: React.FC<TerminalTextHoverEffectProps> = ({ children, className }) => {
  const [isHovered, setIsHovered] = useState<boolean>(false);
 
  const handleMouseEnter = (): void => setIsHovered(true);
  const handleMouseLeave = (): void => setIsHovered(false);
 
  return (
    <div
      className={cn("flex items-start font-mono", className)}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      <TerminalText trigger={isHovered}>{children}</TerminalText>
    </div>
  );
};
 
export default TerminalTextHoverEffect;

Update the import paths to match your project setup.

Props

PropTypeDefaultDescription
childrenstringundefinedThe string that you want the hover effect on
classNamestringundefinedAdditional CSS classes to apply to the div
built by abhiroop. source code available on github.