Input with Cycling Placeholders in React

Demo

import { Input } from '@/components/ui/input';
import useEmblaCarousel from 'embla-carousel-react';
import Autoplay from 'embla-carousel-autoplay';
import { useState } from 'react';
import { SearchIcon } from 'lucide-react';

export const PLACEHOLDERS = [
  'Search for products...',
  'Try "wireless headphones with noise cancellation"',
  'Find "gaming laptop with RTX 4090"',
  'Search "smart watch with heart rate monitor"',
  'Look for "fitness tracker with sleep tracking"',
];

function App() {
  const [value, setValue] = useState('');
  const [isFocused, setIsFocused] = useState(false);
  const [emblaRef] = useEmblaCarousel(
    {
      loop: true,
      axis: 'y',
    },
    [
      Autoplay({
        delay: 3000,
        stopOnInteraction: false,
        stopOnMouseEnter: true,
      }),
    ],
  );

  return (
    <div className="container">
      <div className="mx-auto max-w-7xl px-4">
        <div className="relative">
          <SearchIcon className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-gray-500 z-10" />

          <Input
            className="pl-10"
            value={value}
            onChange={(e) => setValue(e.target.value)}
            onFocus={() => setIsFocused(true)}
            onBlur={() => setIsFocused(false)}
          />

          {value.length === 0 && !isFocused && (
            <div
              className="absolute inset-0 overflow-hidden pointer-events-none text-muted-foreground/80"
              ref={emblaRef}
            >
              <div className="flex flex-col h-10">
                {PLACEHOLDERS.map((placeholder, index) => (
                  <div
                    key={index}
                    className="flex-[0_0_100%] min-h-10 flex items-center px-10"
                  >
                    <span className="truncate">{placeholder}</span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

export default App;