Input
Interactive UI Explorer
아래에서 각 컴포넌트의 다양한 Variants와 States를 문서화된 형태로 테스트해볼 수 있습니다.
Live Preview
홍길동
user@bad
유효한 이메일이 아닙니다
수정 불가
Input
다양한 상태를 지원하는 입력 필드 컴포넌트입니다.
Basic Input
기본 입력 필드
Email
Live Preview
Password
Live Preview
States
입력 필드의 다양한 상태 (error, disabled, helper text)
Error
이 필드는 필수입니다.
Live Preview
Disabled
Live Preview
Helper Text
도움말 텍스트가 여기에 표시됩니다.
Live Preview
Implementation
제작 코드
이 컴포넌트가 실제로 어떻게 구현되어 있는지 — 본체 .tsx 파일을 그대로 보여줍니다. variant 매핑·접근성 처리·forwardRef 패턴 등 디테일을 그대로 확인할 수 있어요.
Inputtypescript
/**
* Input 컴포넌트
*
* Select·Textarea·Checkbox·Radio와 동일 디자인 토큰:
* - 기본 border slate-300 → hover slate-400
* - focus: violet-500 border + violet-500/20 ring
* - error: rose-400 border, focus 시 rose-500 + rose-500/20 ring
* - placeholder slate-400, body text slate-900
* - rounded-xl + shadow-sm
*/
import { InputHTMLAttributes, forwardRef, useId } from 'react';
import { cn } from '@/lib/cn';
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
helperText?: string;
fullWidth?: boolean;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, label, error, helperText, fullWidth, id, ...props }, ref) => {
const generatedId = useId();
const inputId = id ?? `input-${generatedId.replace(/:/g, '-')}`;
return (
<div className={cn('space-y-1.5', fullWidth && 'w-full')}>
{label && (
<label
htmlFor={inputId}
className="block text-xs font-semibold text-slate-700"
>
{label}
</label>
)}
<input
ref={ref}
id={inputId}
className={cn(
'w-full rounded-xl border bg-white px-4 py-2 text-sm text-slate-900 shadow-sm transition-colors',
'placeholder:text-slate-400',
'focus:outline-none',
'disabled:cursor-not-allowed disabled:bg-slate-50 disabled:opacity-60',
'read-only:bg-slate-50 read-only:cursor-default',
error
? 'border-rose-400 focus:border-rose-500 focus:ring-2 focus:ring-rose-500/20'
: 'border-slate-300 hover:border-slate-400 focus:border-violet-500 focus:ring-2 focus:ring-violet-500/20',
className,
)}
aria-invalid={error ? 'true' : 'false'}
aria-describedby={error ? `${inputId}-error` : helperText ? `${inputId}-helper` : undefined}
{...props}
/>
{error && (
<p id={`${inputId}-error`} className="text-xs font-medium text-rose-600">
{error}
</p>
)}
{helperText && !error && (
<p id={`${inputId}-helper`} className="text-xs text-slate-500">
{helperText}
</p>
)}
</div>
);
},
);
Input.displayName = 'Input';