Bonbon TextField 데모
bonbon/textfield는 Radix Slot 기반 compound 컴포넌트와 TextFieldSingleLine·TextFieldMultiLine 래퍼를 제공합니다. SingleLine은 grapheme 기준 characterLimit을 사용합니다.
import
import {
TextField,
TextFieldSingleLine,
TextFieldMultiLine,
} from "@/shared/components/bonbon/textfield";SingleLine — 기본
라벨·입력·도움말을 한 컴포넌트로 묶습니다.
도움말
SingleLine — characterLimit + onValueChange
DOM maxLength 대신 grapheme 기준 characterLimit을 사용합니다.
const [value, setValue] = useState("");
<TextFieldSingleLine
id="title"
label="제목"
inputProps={{
value,
onValueChange: setValue,
placeholder: "플레이스 홀더",
characterLimit: 50,
showCount: true,
clearable: true,
}}
/>10/50
현재 값: 자유롭게 그린 그림
SingleLine — 이모지 grapheme 카운트
👨👩👧👦는 화면에서 1글자지만 JS String.length는 더 큽니다.
1/50
보이는 글자 수: 1 / JS length: 11
SingleLine — 라벨 없음 / error / success / disabled
error는 TextField.Root에 전달되며, showCount일 때 TextField.CharacterCount가 context를 읽어 카운트 색도 함께 바뀝니다.
8/50
에러 도움말
성공 도움말
6/50
비활성 도움말
MultiLine — 기본
textareaProps.maxLength는 native maxLength를 사용합니다.
0/200
도움말
MultiLine — 제어 + 커스텀 높이
0/300
현재 값: «빈 문자열»
Compound — TextField.Root
SingleLine·MultiLine 내부 카운트도 동일한 TextField.CharacterCount를 사용합니다.
0/100
compound API로 레이아웃을 직접 구성한 예시입니다.
CharacterCount — error / disabled (context)
TextField.Root의 error·disabled를 CharacterCount가 context로 반영합니다.
<TextField.Root id="title" error>
...
<TextField.CharacterCount current={12} max={50} />
</TextField.Root>9/50
카운트가 semantic-error 색입니다.
9/50
Zod 검증 시 주의
UI와 동일한 기준으로 검증하려면 isTextInputWithinMaxLength를 사용하세요.
import { isTextInputWithinMaxLength } from "@/shared/lib/textInputPolicy";
const schema = z.object({
title: z
.string()
.trim()
.min(1)
.refine((value) => isTextInputWithinMaxLength(value, 50)),
});