@olundot/ui · Form
Checkbox
넓고 안정적인 터치 영역을 제공하는 불리언·체크리스트·다중 선택 컨트롤입니다.
- 크기
- sm · md
- 상태
- unchecked · checked · indeterminate · disabled
- 접근성 기준
- 44px hit target + visible label + aria-checked=mixed (indeterminate 시)
기본
interactive (라이브 토글 · description sibling)입장 전 필수 확인 항목입니다.
코드 보기tsx
import { Checkbox } from "@olundot/ui";
export function PolicyCheckbox() {
return (
<Checkbox
name="confirm"
label="시험 정책을 확인했습니다."
description="입장 전 필수 확인 항목입니다."
/>
);
}체크리스트
interactive (체크리스트 라이브 토글 · 비활성 포함)응시 직후 즉시 전송됩니다.
기관 정책으로 잠겨 있습니다.
코드 보기tsx
import { Checkbox } from "@olundot/ui";
export function FilterChecklist() {
return (
<div style={{ display: "grid", gap: "12px" }}>
<Checkbox name="f1" label="자동 제출" defaultChecked />
<Checkbox name="f2" label="결과 메일 발송" description="응시 직후 즉시 전송됩니다." />
<Checkbox name="f3" label="외부 공유" disabled description="기관 정책으로 잠겨 있습니다." />
</div>
);
}상태
라이브 토글 (off · on · indeterminate 3-cycle) · disabled코드 보기tsx
import { useState } from "react";
import { Checkbox, type CheckboxCheckedState } from "@olundot/ui";
// off/on은 uncontrolled defaultChecked로 라이브 토글, indeterminate는 controlled
// 3-cycle (off → indeterminate → on → off) — 사용자가 클릭하며 3 상태 학습.
// disabled 2개는 정적 (비활성은 상호작용 X).
export function CheckboxStates() {
const [tri, setTri] = useState<CheckboxCheckedState>("indeterminate");
return (
<div style={{ display: "grid", gap: "12px" }}>
<Checkbox name="off" label="기본 (off)" />
<Checkbox name="on" label="선택됨" defaultChecked />
<Checkbox
name="mix"
label="부분 선택 (클릭하면 3-cycle)"
checked={tri}
onCheckedChange={(next) => {
// 3-cycle: indeterminate → on → off → indeterminate
if (tri === "indeterminate") setTri(true);
else if (tri === true) setTri(false);
else setTri("indeterminate");
void next; // Radix가 자동 토글하려 하지만 우리가 cycle 강제
}}
/>
<Checkbox name="d-off" label="비활성 off" disabled />
<Checkbox name="d-on" label="비활성 on" defaultChecked disabled />
</div>
);
}필수 동의 + 검증
라이브 (* marker · submit 검증 · error 노출)코드 보기tsx
import { useState } from "react";
import { Button, Checkbox } from "@olundot/ui";
// required prop → label 옆 * marker 자동 (aria-hidden, Input/Select 정합).
// submit 미체크 시 error prop 노출 — description 자리에 빨강 메시지 표시 (a11y 표준).
// 체크 시 error 즉시 해제 (FormField 패턴과 동일한 description ↔ error 교체).
export function CheckboxRequiredLive() {
const [agreed, setAgreed] = useState(false);
const [error, setError] = useState<string | undefined>();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!agreed) setError("필수 동의 항목입니다.");
else setError(undefined);
};
return (
<form onSubmit={handleSubmit} style={{ display: "grid", gap: "12px" }}>
<Checkbox
name="agree"
label="시험 정책에 동의합니다."
description="등록 전 필수 확인입니다."
required
checked={agreed}
onCheckedChange={(c) => { setAgreed(c === true); if (c) setError(undefined); }}
error={error}
/>
<Button type="submit">제출</Button>
</form>
);
}