# Text Field Input URL: /react/components/text-field-input Source: https://github.com/daangn/seed-design/blob/dev/docs/content/react/components/text-field-input.mdx 한 줄 텍스트를 입력받는 컴포넌트입니다. 사용 가능 버전: @seed-design/react@1.1.0, @seed-design/css@1.1.0 ## Preview ```tsx import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldPreview() { return ( ); } ``` ## Installation - npm: npx @seed-design/cli@latest add ui:text-field - pnpm: pnpm dlx @seed-design/cli@latest add ui:text-field - yarn: yarn dlx @seed-design/cli@latest add ui:text-field - bun: bun x @seed-design/cli@latest add ui:text-field ## Props ### `TextField` ### `TextFieldInput` ## Examples ### State #### Enabled ```tsx import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputEnabled() { return ( ); } ``` #### Disabled ```tsx import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputDisabled() { return ( ); } ``` #### Read Only ```tsx import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputReadOnly() { return ( ); } ``` ### Size `size`로 TextField의 크기를 정합니다. (default: `large`) `responsive`는 화면 너비에 따라 size가 자동으로 전환되는 값입니다. 여러 화면 너비를 함께 지원하는 제품에서 `size=responsive`를 사용하여 대응합니다. ```tsx import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputSize() { return ( ); } ``` ### Customizable Parts 아이콘만으로 맥락을 전달하려고 할 때 유의하세요. `description` 또는 `label`에 아이콘의 의미를 명확히 설명하는 텍스트를 포함하거나, 아이콘이 스크린 리더에 의해 읽히도록 설정하고 `aria-label`을 제공하세요. #### Prefix ```tsx import { IconMagnifyingglassLine } from "@karrotmarket/react-monochrome-icon"; import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputPrefix() { return ( } > } > ); } ``` #### Suffix ```tsx import { IconWonLine } from "@karrotmarket/react-monochrome-icon"; import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputSuffix() { return ( }> }> ); } ``` #### Both Affixes ```tsx import { IconPlusCircleLine, IconWonLine } from "@karrotmarket/react-monochrome-icon"; import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputBothAffixes() { return ( } suffixIcon={} > } suffixIcon={} > ); } ``` #### Indicator `indicator` 또는 `showRequiredIndicator` prop을 사용할 수 있습니다. ```tsx import { HStack } from "@seed-design/react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputIndicator() { return ( ); } ``` #### Grapheme Count ```tsx import { TextField, TextFieldInput } from "seed-design/ui/text-field"; import { HStack } from "@seed-design/react"; export default function TextFieldInputGraphemeCount() { return ( ); } ``` 자소 단위로 쪼개진 `value`에 관한 정보를 `onValueChange` 콜백에서 `graphemes`와 `slicedGraphemes`로 제공합니다. 자소 분리는 [unicode-segmenter](https://github.com/cometkim/unicode-segmenter)를 통해 이루어집니다. ```tsx import { TextField, TextFieldInput } from "seed-design/ui/text-field"; import { useState } from "react"; import { Text, VStack } from "@seed-design/react"; export default function TextFieldInputGraphemeControlled() { const [value, setValue] = useState(""); const [graphemes, setGraphemes] = useState([]); return ( { setValue(slicedValue); setGraphemes(slicedGraphemes); }} >
graphemes.length: {graphemes.length} value.length: {value.length} graphemes: {JSON.stringify(graphemes)} value: {value}
); } ``` ### Use Cases #### Form (Uncontrolled) ```tsx import { HStack, VStack } from "@seed-design/react"; import { useCallback, useState, type FormEvent } from "react"; import { ActionButton } from "seed-design/ui/action-button"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; type FieldErrors = { name?: string; address?: string; }; export default function TextFieldInputForm() { const [fieldErrors, setFieldErrors] = useState({}); const handleSubmit = useCallback((event: FormEvent) => { event.preventDefault(); const formData = new FormData(event.currentTarget); const name = formData.get("name")?.toString(); const address = formData.get("address")?.toString(); const newFieldErrors: FieldErrors = {}; if (!name) { newFieldErrors.name = "필수 입력 항목입니다"; } if (!address) { newFieldErrors.address = "필수 입력 항목입니다"; } if (address && !address.startsWith("대한민국")) { newFieldErrors.address = "대한민국으로 시작해주세요"; } setFieldErrors(newFieldErrors); if (Object.keys(newFieldErrors).length > 0) return; window.alert(JSON.stringify(Object.fromEntries(formData.entries()), null, 2)); }, []); return (
제출
); } ``` #### React Hook Form ```tsx import { HStack, VStack } from "@seed-design/react"; import { useCallback, type FormEvent } from "react"; import { useController, useForm } from "react-hook-form"; import { ActionButton } from "seed-design/ui/action-button"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; interface FormValues { name: string; address: string; } export default function TextFieldInputReactHookForm() { const { handleSubmit, reset, control } = useForm({ reValidateMode: "onSubmit", defaultValues: { name: "", address: "", }, }); const { field: { onChange: nameOnChange, ...nameField }, fieldState: nameFieldState, } = useController({ name: "name", control, rules: { required: "필수 입력 항목입니다", }, }); const { field: { onChange: addressOnChange, ...addressField }, fieldState: addressFieldState, } = useController({ name: "address", control, rules: { required: "필수 입력 항목입니다", pattern: { value: /^대한민국/, message: "대한민국으로 시작해주세요" }, }, }); const onValid = useCallback((data: FormValues) => { window.alert(JSON.stringify(data, null, 2)); }, []); const onReset = useCallback( (event: FormEvent) => { event.preventDefault(); reset(); }, [reset], ); return ( nameOnChange(value)} required showRequiredIndicator {...nameField} > addressOnChange(slicedValue)} required showRequiredIndicator {...addressField} > 초기화 제출 ); } ``` #### Number Formatting ```tsx import { useMemo, useState } from "react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputNumberFormatting() { const [value, setValue] = useState("1000"); const formattedValue = useMemo(() => { if (value === "") return value; const number = Number(value.replace(/,/g, "")); if (Number.isNaN(number)) return ""; return number.toLocaleString(); }, [value]); return ( setValue(value)} > ); } ``` #### Slicing ```tsx import { useState } from "react"; import { TextField, TextFieldInput } from "seed-design/ui/text-field"; export default function TextFieldInputSlicing() { const [value, setValue] = useState(""); return ( setValue(slicedValue)} > ); } ```