이번에는 shadcn ui form을 설치를 한 후 간단한 로그인 폼을 제작해보았습니다.
https://ui.shadcn.com/docs/components/form#installation
다음 링크를 통해 form을 깔아주면
- react-hook-form → 폼 상태 관리 라이브러리
- @hookform/resolvers → react-hook-form과 zod 같은 스키마 검증 라이브러리를 연결하는 역할
- zod → 입력 값 검증을 위한 스키마 정의 라이브러리
다음과 같은 라이브러리가 깔린
처음 zod 라이브러리가 깔린 것을 봤을 때 사용해보지 못하여서 개념에 대한 공부를 해보았다.
🛠 zod란? (입력 값 검증 라이브러리)
zod는 입력 값의 유효성을 검사하는 라이브러리로, 폼 입력값이 올바른지 확인하는 데 사용됩니다.
- zod의 주요 특징
- 스키마 기반 검증 → z.object({})를 이용해 데이터 구조를 정의하고 검증 수행
- 타입스크립트 친화적 → 입력 데이터의 타입을 자동으로 추론
- 체이닝 방식 검증 → .min(), .max(), .email() 등 다양한 메서드를 사용해 유효성 검사 가능
🛠 zod를 사용한 폼 검증 예제
import { z } from 'zod'; export const formSchema = z.object({ username: z.string().min(2, '이름은 최소 2자 이상이어야 합니다.').max(50, '최대 50자까지 입력 가능합니다.'), password: z.string().min(6, '비밀번호는 최소 6자 이상이어야 합니다.'), }); export type FormSchemaType = z.infer<typeof formSchema>;이 코드는 zod를 사용해 입력값이 올바른지 검증하는 스키마를 정의한 것입니다.
username은 최소 2자 이상, 최대 50자 이하로 제한
password는 최소 6자 이상 입력해야 유효
ShadCN UI의 Form 컴포넌트
ShadCN UI는 react-hook-form과 함께 사용할 수 있도록 폼 컴포넌트를 제공합니다.
특히 Form, FormField, FormItem, FormLabel, FormControl, FormMessage 등을 활용하면 깔끔하고 일관된 스타일의 폼을 손쉽게 구성할 수 있습니다.
다음은 zod와 훅폼을 사용한 컴포넌트 작성 코드입니다.
//데이터 유효성에 관한 스키마 정의
//formSchema.ts
import { z } from 'zod';
export const formSchema = z.object({
username: z
.string()
.min(2, '이름은 최소 2자 이상이어야 합니다.')
.max(50, '최대 50자까지 입력 가능합니다.'),
password: z.string().min(6, '비밀번호는 최소 6자 이상이어야 합니다.'),
});
export type FormSchemaType = z.infer<typeof formSchema>;
//임시로 만든 회원가입 폼
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { FormSchemaType, formSchema } from '@/schemas/formSchema';
import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import {
Card,
CardHeader,
CardTitle,
CardContent,
CardFooter,
} from '@/components/ui/card';
import { Eye, EyeOff, Lock, User } from 'lucide-react';
import { useState } from 'react';
const AuthForm = () => {
const form = useForm<FormSchemaType>({
resolver: zodResolver(formSchema),
defaultValues: {
username: '',
password: '',
},
});
const [showPassword, setShowPassword] = useState(false);
const onSubmit = (values: FormSchemaType) => {
alert(
`회원가입에 성공하였습니다!!\n이름 : ${values.username} \n비번 : ${values.password}`,
);
};
return (
<Card className="w-[400px] border border-gray-200 shadow-lg">
<CardHeader>
<CardTitle className="text-center text-2xl font-bold">
회원가입
</CardTitle>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-5">
{/* Username 필드 */}
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<div className="relative">
<User
className="absolute left-3 top-1/2 -translate-y-1/2 transform text-gray-400"
size={18}
/>
<Input
placeholder="홍길동"
{...field}
className="pl-10"
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Password 필드 */}
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<div className="relative">
<Lock
className="absolute left-3 top-1/2 -translate-y-1/2 transform text-gray-400"
size={18}
/>
<Input
type={showPassword ? 'text' : 'password'}
placeholder="비밀번호 입력"
{...field}
className="pl-10 pr-10"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 transform text-gray-400"
>
{showPassword ? (
<EyeOff size={18} />
) : (
<Eye size={18} />
)}
</button>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<CardFooter className="flex flex-col gap-3">
<Button type="submit" className="w-full">
회원가입
</Button>
<p className="text-center text-sm text-gray-500">
이미 계정이 있으신가요?{' '}
<a href="" className="text-blue-500 hover:underline">
로그인
</a>
</p>
</CardFooter>
</form>
</Form>
</CardContent>
</Card>
);
};
export default AuthForm;
추가적인 디자인을 위한 card, button 컴포넌트를 추가했습니다.
또한 학습을 목적으로 했기 때문에 컴포넌트 분리, 최적화 등을 추가적으로 하지 않았습니다.
또 한 가지 흥미로웠던 점이 shadcn-ui의 form 컴포넌트를 추가할 때 자동으로 lucide-react도 함께 설치되어서 아이콘을 바로 사용할 수 있다는 점이다.
마지막으로 코드에 관한 간단한 설명
- useForm을 활용한 폼 상태 관리
react-hook-form의 useForm을 사용해 폼 상태를 관리하고,
zodResolver를 통해 Zod 스키마 검증을 적용- 입력 필드 (Username & Password)
FormField, FormItem, FormControl을 사용해 shadcn/ui 스타일을 적용.
lucide-react 아이콘(User, Lock, Eye, EyeOff)을 활용하여 UI 개선.
비밀번호 필드에 토글 버튼을 추가하여 Eye, EyeOff 아이콘으로 비밀번호 가리기/보이기 기능 제공.- 카드 UI (Shadcn UI Card 컴포넌트 사용)
Card, CardHeader, CardTitle, CardContent, CardFooter를 활용해 회원가입 UI 디자인.- 폼 제출 (회원가입)
onSubmit 함수에서 입력값을 받아 alert 창으로 확인하도록 구현.
