Floating Label Input

Text field whose label floats up on focus — pure CSS.

Create your account

We'll never share your email.

Installation

  1. Install the dependencies

    $ npm i motion lucide-react
  2. Copy the source into components/ui/floating-input.tsx

    components/ui/floating-input.tsx
    "use client";
    
    import { useId, type InputHTMLAttributes } from "react";
    
    type FloatingInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "placeholder"> & {
      label: string;
      hint?: string;
    };
    
    export function FloatingInput({ label, hint, className = "", id, ...props }: FloatingInputProps) {
      const autoId = useId();
      const inputId = id ?? autoId;
    
      return (
        <div className={className}>
          <div className="relative">
            <input
              id={inputId}
              placeholder=" "
              className="peer block w-full rounded-xl border border-zinc-200 bg-white px-4 pb-2.5 pt-6 text-sm text-zinc-900 outline-none transition focus:border-blue-600 focus:ring-4 focus:ring-blue-600/10"
              {...props}
            />
            <label
              htmlFor={inputId}
              className="pointer-events-none absolute left-4 top-4 origin-left text-sm text-zinc-500 transition-all duration-200 peer-focus:top-2 peer-focus:text-xs peer-focus:text-blue-600 peer-[:not(:placeholder-shown)]:top-2 peer-[:not(:placeholder-shown)]:text-xs"
            >
              {label}
            </label>
          </div>
          {hint && <p className="mt-1.5 px-1 text-xs text-zinc-500">{hint}</p>}
        </div>
      );
    }
    
    export default function Demo() {
      return (
        <form onSubmit={(e) => e.preventDefault()} className="w-full max-w-sm space-y-3 rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm">
          <h3 className="mb-2 text-lg font-semibold text-zinc-900">Create your account</h3>
          <FloatingInput label="Full name" autoComplete="name" />
          <FloatingInput label="Work email" type="email" autoComplete="email" hint="We'll never share your email." />
          <button className="w-full rounded-xl bg-zinc-900 py-3 text-sm font-medium text-white transition hover:bg-zinc-800">Continue</button>
        </form>
      );
    }
    
  3. Use it

    The file exports the component and a Demo showing typical usage. Import whichever you need.