Skip to content
Docs
Underline hover text

Underline hover text

A customizable text component with an underline hover effect.

requires interactionhover
Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/text/underline-hover-text.json

Manual

Run the following command

It will create a new file called underline-hover-text.tsx inside the components/animata/text directory.

mkdir -p components/animata/text && touch components/animata/text/underline-hover-text.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
import type React from "react";
 
import { cn } from "@/lib/utils";
 
export interface UnderlineHoverTextProps {
  text: string;
  /**
   * Resting text color. Tailwind class string.
   */
  textColor?: string;
  /**
   * Text color applied on hover. Pass `hover:text-foo` style class, or leave
   * empty to keep the resting color.
   */
  hoverTextColor?: string;
  /**
   * Background color class applied to the underline stroke. Pass a plain
   * class like `bg-zinc-900` (or any `bg-*`). The component drives visibility
   * itself via the parent's `:hover` — if you pass a `hover:`-prefixed class
   * here it'll never apply (the stroke element is not the hovered element)
   * and the stroke will appear colorless on hover.
   */
  hoverColor?: string;
  fontSize?: string;
  fontWeight?: string;
  className?: string;
}
 
const UnderlineHoverText: React.FC<UnderlineHoverTextProps> = ({
  text,
  textColor = "text-zinc-900 dark:text-zinc-100",
  hoverTextColor = "",
  hoverColor = "bg-zinc-900 dark:bg-zinc-100",
  fontSize = "text-2xl",
  fontWeight = "font-medium",
  className,
}) => {
  return (
    <span
      className={cn(
        "group/underline relative inline-block cursor-pointer px-1 pb-1.5",
        "tracking-tight",
        "transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)]",
        "will-change-transform hover:-translate-y-[2px]",
        fontSize,
        textColor,
        fontWeight,
        hoverTextColor,
        className,
      )}
    >
      <span className="relative z-10">{text}</span>
      {/* Soft baseline — always present, muted */}
      <span
        aria-hidden
        className="pointer-events-none absolute bottom-0 left-0 h-px w-full bg-current opacity-25"
      />
      {/* Hover stroke — sweeps outward from the center */}
      <span
        aria-hidden
        className={cn(
          "pointer-events-none absolute -bottom-px left-1/2 h-[3px] w-0 -translate-x-1/2 rounded-full",
          "transition-[width] duration-500 ease-[cubic-bezier(0.22,1,0.36,1)]",
          "group-hover/underline:w-full",
          hoverColor,
        )}
      />
    </span>
  );
};
 
export default UnderlineHoverText;

Credits

Built by Chiranjibi Ranabhat