Input
beui/inputFreeComponent
Text input with label, left/right icons, error shake and success check draw.
Install it
npx shadcn@latest add https://beui.dev/r/input.jsonSource
1"use client";2// beui.dev/components/motion/input34import {5 AnimatePresence,6 animate,7 motion,8 useReducedMotion,9} from "motion/react";10import {11 forwardRef,12 useEffect,13 useId,14 useRef,15 useState,16 type InputHTMLAttributes,17 type ReactNode,18} from "react";19import { cn } from "@/lib/utils";2021export type InputClassNames = {22 root?: string;23 label?: string;24 field?: string;25 input?: string;26 leftIcon?: string;27 rightIcon?: string;28 successIcon?: string;29 errorMessage?: string;30};3132export interface InputProps extends Omit<33 InputHTMLAttributes<HTMLInputElement>,34 "value" | "defaultValue" | "onChange"35> {36 label?: string;37 value?: string;38 defaultValue?: string;39 onChange?: (value: string) => void;40 /** Truthy error triggers a shake, red border and (if a string) a message. */41 error?: string | boolean;42 success?: boolean;43 leftIcon?: ReactNode;44 rightIcon?: ReactNode;45 className?: string;46 classNames?: InputClassNames;47}4849export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(50 {51 label,52 value: valueProp,53 defaultValue,54 onChange,55 onFocus,56 onBlur,57 error,58 success,59 leftIcon,60 rightIcon,61 className,62 classNames,63 disabled,64 id: idProp,65 type,66 ...rest67 },68 ref,69) {70 const reactId = useId();71 const id = idProp ?? reactId;72 const reduce = useReducedMotion();7374 const controlled = valueProp !== undefined;75 const [internal, setInternal] = useState(defaultValue ?? "");76 const value = controlled ? (valueProp ?? "") : internal;7778 const [focused, setFocused] = useState(false);7980 const fieldRef = useRef<HTMLDivElement>(null);8182 const hasError = Boolean(error);83 const errorMessage = typeof error === "string" ? error : null;8485 // Right edge shows the success check, otherwise the caller's right icon.86 const rightSlot = success ? null : rightIcon;8788 // Shake the field when an error appears.89 useEffect(() => {90 if (!fieldRef.current || reduce || !hasError) return;91 animate(92 fieldRef.current,93 { x: [0, -6, 6, -4, 4, -2, 0] },94 { duration: 0.45 },95 );96 }, [hasError, reduce]);9798 const handleChange = (next: string) => {99 if (!controlled) setInternal(next);100 onChange?.(next);101 };102103 return (104 <div105 className={cn("flex flex-col gap-1.5", className, classNames?.root)}106 >107 {label ? (108 <label109 htmlFor={id}110 className={cn(111 "px-1 text-sm font-medium text-foreground",112// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
