Text Field

Free

A labeled text input with clear focus and placeholder states.

npx shadcn@latest add @ui-shrushank/text-field

The install writes a single file to components/ui/TextField.tsx, which exports TextField.

tsx
import { TextField } from "@/components/ui/TextField";
tsx
<TextField label="Label" />

The labelled input baseline.

Always a real <label>, distinct focus and placeholder states, custom focus ring with the browser outline suppressed.

Every line below was read out of the file you are about to copy, so you can check each one against the source at the bottom of this page.

  • Draws a focus-visible ring that is separate from its hover treatment, so keyboard users get an affordance mouse users do not take away.
  • Pairs every input with a real <label>, so the field keeps its name after the placeholder disappears.

Placeholder text is not a label substitute (it vanishes on type); pairing them removes the "what was this field?" problem once the user starts typing.

1 required, 0 optional.

labelrequired
string

One file, no runtime package. Copy it, or install it with the command at the top of this page.

TextField.tsx
export function TextField({ label }: { label: string }) {  return (    <div className="relative w-full">      <input        id="text-field"        type="text"        placeholder=" "        className="peer w-full rounded-lg border border-stone-300 bg-white px-3.5 pb-2 pt-5 text-sm text-stone-900 outline-none transition-colors focus:border-emerald-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-600 dark:border-stone-600 dark:bg-neutral-950 dark:text-white"      />      <label        htmlFor="text-field"        className="pointer-events-none absolute left-3.5 top-1/2 -translate-y-1/2 text-sm text-stone-400 transition-all duration-200 ease-out peer-focus:top-3.5 peer-focus:text-xs peer-focus:text-emerald-700 peer-[:not(:placeholder-shown)]:top-3.5 peer-[:not(:placeholder-shown)]:text-xs peer-[:not(:placeholder-shown)]:text-stone-500 dark:peer-[:not(:placeholder-shown)]:text-stone-400"      >        {label}      </label>      <span className="pointer-events-none absolute inset-x-3.5 bottom-1.5 h-px origin-left scale-x-0 bg-emerald-600 transition-transform duration-300 ease-out peer-focus:scale-x-100" />    </div>  );}