Skip to Content

Input

Text input field with optional label, helper text, and error state. Supports all standard input types.

Design Language Comparison

Neobrutalism
Shadcn-inspired
Flowbite-inspired
Glassmorphism
Material Design 3
Neumorphism

Neobrutalism

Thick border, flat box shadow, yellow focus highlight.

const NeobrutalismInput = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1 font-sans">
      {label && (
        <label htmlFor={inputId} className="text-[0.8125rem] font-extrabold text-black">
          {label}
        </label>
      )}
      <input
        id={inputId}
        type={type}
        value={inputValue}
        placeholder={placeholder}
        disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        className={[
          "py-2 px-3 text-[0.9375rem] font-sans text-black bg-white border-[3px] border-black rounded-[2px] shadow-[4px_4px_0_#000] outline-none w-full",
          "placeholder:text-[#333] placeholder:opacity-60",
          "focus:shadow-[6px_6px_0_#000] focus:bg-yellow-400 focus:-translate-x-px focus:-translate-y-px",
          "disabled:bg-gray-300 disabled:text-gray-500 disabled:border-gray-500 disabled:shadow-none disabled:cursor-not-allowed",
          error ? "border-red-500 shadow-[4px_4px_0_#ef4444]" : "",
        ].filter(Boolean).join(" ")}
      />
      {error && <span className="text-[0.8125rem] text-red-500 font-extrabold">{error}</span>}
      {helperText && !error && <span className="text-[0.8125rem] text-[#333]">{helperText}</span>}
    </div>
  );
};

Shadcn-inspired

Zinc border, 6 px radius, ring-offset focus style.

const ShadcnInput = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1.5 font-sans">
      {label && (
        <label htmlFor={inputId} className="text-sm font-medium text-zinc-900">
          {label}
        </label>
      )}
      <input
        id={inputId}
        type={type}
        value={inputValue}
        placeholder={placeholder}
        disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        className={[
          "py-2 px-3 text-[0.9375rem] font-sans text-zinc-900 bg-white border border-zinc-200 rounded-[6px] outline-none w-full transition-[border-color,box-shadow] duration-150",
          "placeholder:text-zinc-500",
          "focus:border-zinc-900 focus:shadow-[0_0_0_2px_#18181b]",
          "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-zinc-100",
          error ? "border-red-500 focus:shadow-[0_0_0_2px_#ef4444]" : "",
        ].filter(Boolean).join(" ")}
      />
      {error && <span className="text-sm text-red-500">{error}</span>}
      {helperText && !error && <span className="text-sm text-zinc-500">{helperText}</span>}
    </div>
  );
};

Flowbite-inspired

Blue focus ring, 8 px radius, smooth transition.

const FlowbiteInput = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1.5 font-sans">
      {label && (
        <label htmlFor={inputId} className="text-sm font-medium text-gray-900">
          {label}
        </label>
      )}
      <input
        id={inputId}
        type={type}
        value={inputValue}
        placeholder={placeholder}
        disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        className={[
          "py-2 px-3 text-[0.9375rem] font-sans text-gray-900 bg-white border border-gray-200 rounded-lg shadow-sm outline-none w-full transition-all duration-200",
          "placeholder:text-gray-500",
          "focus:border-[#1c64f2] focus:shadow-[0_0_0_3px_rgba(28,100,242,0.3)]",
          "disabled:bg-gray-100 disabled:text-gray-400 disabled:cursor-not-allowed",
          error ? "border-[#e02424] focus:shadow-[0_0_0_3px_rgba(224,36,36,0.3)]" : "",
        ].filter(Boolean).join(" ")}
      />
      {error && <span className="text-sm text-[#e02424]">{error}</span>}
      {helperText && !error && <span className="text-sm text-gray-500">{helperText}</span>}
    </div>
  );
};

Glassmorphism

Translucent input on gradient background with blur effect.

const GlassmorphismInput = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1.5 font-sans">
      {label && <label htmlFor={inputId} className="text-sm font-medium text-white/90">{label}</label>}
      <input
        id={inputId} type={type} value={inputValue} placeholder={placeholder} disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        className={["py-2 px-3 text-[0.9375rem] text-white bg-white/10 backdrop-blur-md border border-white/20 rounded-xl outline-none w-full transition-all duration-200 placeholder:text-white/50 focus:border-white/50 focus:bg-white/20 disabled:opacity-40 disabled:cursor-not-allowed", error ? "border-red-400/60" : ""].filter(Boolean).join(" ")}
      />
      {error && <span className="text-sm text-red-300">{error}</span>}
      {helperText && !error && <span className="text-sm text-white/60">{helperText}</span>}
    </div>
  );
};

Material Design 3

Bottom-border outlined field with label colour transition on focus.

const Md3Input = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const [focused, setFocused] = useState(false);
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1 font-sans">
      {label && (
        <label htmlFor={inputId} className={`text-xs font-medium ${error ? "text-[#b3261e]" : focused ? "text-[#6750a4]" : "text-[#49454f]"}`}>{label}</label>
      )}
      <input
        id={inputId} type={type} value={inputValue} placeholder={placeholder} disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
        className={["py-2 px-4 text-[0.9375rem] text-[#1c1b1f] bg-[#fffbfe] border rounded-[4px] outline-none w-full transition-all duration-200 placeholder:text-[#49454f] disabled:opacity-40 disabled:cursor-not-allowed", error ? "border-[#b3261e] border-b-2" : focused ? "border-[#6750a4] border-b-2" : "border-[#79747e]"].join(" ")}
      />
      {error && <span className="text-xs text-[#b3261e]">{error}</span>}
      {helperText && !error && <span className="text-xs text-[#49454f]">{helperText}</span>}
    </div>
  );
};

Neumorphism

Concave inset shadow gives the field a pressed-in appearance.

const NmInput = ({ value, onChange, placeholder = "", disabled = false, type = "text", label, error, helperText, id }) => {
  const [inputValue, setInputValue] = useState(value ?? "");
  const inputId = id ?? (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);

  return (
    <div className="flex flex-col gap-1.5 font-sans">
      {label && <label htmlFor={inputId} className="text-sm font-semibold text-[#6c7a9c]">{label}</label>}
      <input
        id={inputId} type={type} value={inputValue} placeholder={placeholder} disabled={disabled}
        onChange={(e) => { setInputValue(e.target.value); onChange?.(e); }}
        className="py-2.5 px-4 text-[0.9375rem] text-[#3d4f6e] rounded-xl outline-none w-full border-none bg-[#e0e5ec] shadow-[inset_-5px_-5px_10px_#ffffff,_inset_5px_5px_10px_rgba(163,177,198,0.6)] placeholder:text-[#6c7a9c]/60 focus:shadow-[inset_-3px_-3px_7px_#ffffff,_inset_3px_3px_7px_rgba(163,177,198,0.5)] disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-150"
      />
      {error && <span className="text-sm text-red-500">{error}</span>}
      {helperText && !error && <span className="text-sm text-[#6c7a9c]">{helperText}</span>}
    </div>
  );
};
Last updated on

© 2026 UI Variants. Built with Nextra.