react - 예쁜 체크박스를 만들어보자
🧡 체크박스와 어드민
admin 페이지를 만들다 보면 가장 자주 마주하는 UI 중 하나가 바로 테이블과 체크박스(checkbox) / 라디오 버튼(radio)이다. 관리자 페이지는 실제 사용자가 빠르게 정보를 파악하고 입력할 수 있어야 하기 때문에, UI의 작은 요소 하나도 “한눈에 들어오는가?”가 매우 중요하다.
하지만 기본 제공되는 <input type="checkbox"> 형태는 디자인 커스터마이징에 제약이 있어, 대부분 별도의 스타일을 입히거나 완전히 커스텀 컴포넌트를 만들어 사용하게 된다.
최근 체크박스를 커스텀할 일이 자주 있어서, 그동안 자주 사용했던 두 가지 방식을 간단하게 정리해본다
⭐ state를 사용하자
첫 번째 방법은 state로 체크 여부를 직접 관리하는 방식이다. 가장 간단하고, 원하는 형태로 UI를 자유롭게 만들기 좋다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { useState } from "react"
import { Check } from "lucide-react"
import { cn } from "@/utils/cn"
interface CheckboxProps {
label?: string
defaultChecked?: boolean
onChange?: (checked: boolean) => void
}
export default function Checkbox({
label = "",
defaultChecked = false,
onChange,
}: CheckboxProps) {
const [checked, setChecked] = useState(defaultChecked)
const handleClick = () => {
const newValue = !checked
setChecked(newValue)
onChange?.(newValue)
}
return (
<label
className="flex items-center gap-2 cursor-pointer select-none"
onClick={handleClick}
>
<span
className={cn(
"w-5 h-5 rounded-md border flex items-center justify-center transition-all",
checked
? "bg-indigo-600 border-indigo-600"
: "bg-white border-gray-400"
)}
>
{checked && <Check size={14} className="text-white" />}
</span>
{label}
</label>
)
}
🌟 input을 사용하자
두 번째 방식은 기본 input 요소를 유지하면서 외형만 커스텀하는 방식이다. 내가 선호하는 방식인데 장점은 다음과 같다.
- register를 통해 react-hook-form과 자연스럽게 연결됨
- label 클릭으로 체크가 toggled 되어 접근성이 좋음
- input은 숨겨두고, 디자인은 label 또는 span에 입히는 구조라서 유지보수에 좋음
구현 핵심은 input은 sr-only로 감추고, 시각적 체크박스는 label 내부의 span으로 구현하는 것이다.
1
2
3
4
5
<label className="flex items-center gap-2 cursor-pointer">
<input type="checkbox" {...register("isActive")} className="sr-only" />
<span className="custom-checkbox"></span>
활성화 여부
</label>
This post is licensed under CC BY 4.0 by the author.