Back

Peektext

Inline Hover Reveal

He works at Equicom Technologies building products.

Component Code (Next.js)

"use client";

import { useState } from "react";
import Image from "next/image";

type PeektextProps = {
  text: string;
  image: string;
  imageAlt: string;
};

function Peektext({ text, image, imageAlt }: PeektextProps) {
  const [hovered, setHovered] = useState(false);

  return (
    <span
      className="inline-flex cursor-pointer items-center gap-1 border-b border-dashed border-[color-mix(in_srgb,var(--text-secondary)_10%,var(--border-color))] transition-colors hover:border-[var(--accent)] hover:text-[var(--accent)]"
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      {text}
      <span
        className={`inline-block overflow-hidden transition-all duration-200 ease-in-out ${
          hovered ? "h-8 w-8 opacity-100" : "h-0 w-0 opacity-0"
        }`}
      >
        <Image
          alt={imageAlt}
          className="h-8 w-8 rounded-sm object-cover"
          height={32}
          src={image}
          width={32}
        />
      </span>
    </span>
  );
}

type Segment =
  | { text: string }
  | { text: string; image: string; imageAlt: string };

const segments: Segment[] = [
  { text: "He works at " },
  {
    text: "Equicom Technologies",
    image: "/portfolio/equicom.png",
    imageAlt: "Equicom Technologies",
  },
  { text: " building products." },
];

function isImageSegment(
  segment: Segment,
): segment is { text: string; image: string; imageAlt: string } {
  return "image" in segment;
}

export default function PeektextPage() {
  return (
    <div className="w-full max-w-2xl rounded-2xl border border-[var(--border-color)] bg-white p-6 shadow-sm sm:p-8">
      <p className="text-sm uppercase tracking-[0.14em] text-[var(--text-secondary)]">
        Inline Hover Reveal
      </p>
      <p className="mt-3 text-lg leading-relaxed text-[#111827] sm:text-xl">
        {segments.map((segment, index) =>
          isImageSegment(segment) ? (
            <Peektext
              key={`${segment.text}-${index}`}
              text={segment.text}
              image={segment.image}
              imageAlt={segment.imageAlt}
            />
          ) : (
            <span key={`${segment.text}-${index}`}>{segment.text}</span>
          ),
        )}
      </p>
    </div>
  );
}

Claude / Codex Prompt

Create an inline text component where a tiny image expands on hover. Use Next.js Image and Tailwind classes to transition from w-0 opacity-0 to w-4 opacity-100 in 200ms.