# Text Field Textarea URL: /react/components/text-field-textarea Source: https://github.com/daangn/seed-design/blob/dev/docs/content/react/components/text-field-textarea.mdx 여러 줄의 긴 텍스트를 입력받고 자동으로 높이를 조절하는 컴포넌트입니다. 사용 가능 버전: @seed-design/react@1.1.0, @seed-design/css@1.1.0 ## Preview ```tsx import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function MultilineTextFieldPreview() { 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` ### `TextFieldTextarea` ## Examples ### State #### Enabled ```tsx import { HStack } from "@seed-design/react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaEnabled() { return ( ); } ``` #### Disabled ```tsx import { HStack } from "@seed-design/react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaDisabled() { return ( ); } ``` #### Read Only ```tsx import { HStack } from "@seed-design/react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaReadOnly() { return ( ); } ``` ### Size `size`로 TextField의 크기를 정합니다. (default: `large`) `responsive`는 화면 너비에 따라 size가 자동으로 전환되는 값입니다. 여러 화면 너비를 함께 지원하는 제품에서 `size=responsive`를 사용하여 대응합니다. ```tsx import { HStack, VStack } from "@seed-design/react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaSize() { return ( ); } ``` ### Sizing ``에 `height` 관련 스타일을 직접 지정하여 높이를 고정하거나 최소/최대 높이를 설정할 수 있습니다. #### Fixed Height ```tsx import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaSpecifiedHeight() { return ( ); } ``` #### Auto Height with Constraints ```tsx import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaConstraints() { return ( ); } ``` ### Customizable Parts #### Indicator `indicator` 또는 `showRequiredIndicator` prop을 사용할 수 있습니다. ```tsx import { HStack } from "@seed-design/react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaIndicator() { return ( ); } ``` #### Grapheme Count ```tsx import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaGraphemeCount() { return ( ); } ``` 자소 단위로 쪼개진 `value`에 관한 정보를 `onValueChange` 콜백에서 `graphemes`와 `slicedGraphemes`로 제공합니다. 자소 분리는 [unicode-segmenter](https://github.com/cometkim/unicode-segmenter)를 통해 이루어집니다. ```tsx import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; import { useState } from "react"; import { Text, VStack } from "@seed-design/react"; export default function TextFieldTextareaGraphemeControlled() { 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, TextFieldTextarea } from "seed-design/ui/text-field"; type FieldErrors = { bio?: string; address?: string; }; export default function TextFieldTextareaForm() { const [fieldErrors, setFieldErrors] = useState({}); const handleSubmit = useCallback((event: FormEvent) => { event.preventDefault(); const formData = new FormData(event.currentTarget); const bio = formData.get("bio")?.toString(); const address = formData.get("address")?.toString(); const newFieldErrors: FieldErrors = {}; if (!bio) { newFieldErrors.bio = "필수 입력 항목입니다"; } 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, type KeyboardEvent } from "react"; import { useController, useForm } from "react-hook-form"; import { ActionButton } from "seed-design/ui/action-button"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; interface FormValues { bio: string; address: string; } export default function TextFieldTextareaReactHookForm() { const { handleSubmit, reset, control } = useForm({ reValidateMode: "onSubmit", defaultValues: { bio: "", address: "", }, }); const { field: { onChange: bioOnChange, ...bioField }, fieldState: bioFieldState, } = useController({ name: "bio", 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], ); const onMetaReturn = useCallback( (event: KeyboardEvent) => { if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) { event.preventDefault(); handleSubmit(onValid)(); } }, [handleSubmit, onValid], ); return ( bioOnChange(value)} required showRequiredIndicator {...bioField} > addressOnChange(slicedValue)} required showRequiredIndicator {...addressField} > 초기화 제출 ); } ``` #### Formatting ```tsx import { useMemo, useState } from "react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaFormatting() { const [value, setValue] = useState(""); const formattedValue = useMemo( () => value .split("") .filter((char) => char !== " ") .join(""), [value], ); return ( setValue(value)} > ); } ``` #### Slicing ```tsx import { useState } from "react"; import { TextField, TextFieldTextarea } from "seed-design/ui/text-field"; export default function TextFieldTextareaSlicing() { const [value, setValue] = useState(""); return ( setValue(slicedValue)} > ); } ```