# Field Button URL: /lynx/components/input-button Source: https://github.com/daangn/seed-design/blob/dev/docs/content/lynx/components/input-button.mdx 입력 필드 형태의 버튼으로, 선택창이나 피커를 열 때 사용합니다. 선택이 완료되면 버튼 라벨에 선택된 값이 표시됩니다. 사용 가능 버전: @seed-design/lynx-react@0.7.0, @seed-design/lynx-css@0.11.0 ## Preview ```tsx import "./styles"; import { useCallback, useState } from "@lynx-js/react"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [value, setValue] = useState(null); const selectValue = useCallback(() => { "background only"; setValue("판교동"); }, []); const clearValue = useCallback(() => { "background only"; setValue(null); }, []); return ( {value == null ? ( 동네를 선택해 주세요 ) : ( {value} )} ); } ``` ## Installation - npm: npx @seed-design/cli@latest add ui:field-button - pnpm: pnpm dlx @seed-design/cli@latest add ui:field-button - yarn: yarn dlx @seed-design/cli@latest add ui:field-button - bun: bun x @seed-design/cli@latest add ui:field-button ## Props ### `FieldButton` ### `FieldButtonValue` ### `FieldButtonPlaceholder` ## Examples ### Basic Usage `FieldButton`은 `TextField`와 유사한 외관을 갖지만, 값을 직접 편집하지 않고 선택창이나 피커를 여는 버튼입니다. - **`buttonProps`** - **`bindtap`**: 버튼 tap handler - **`accessibility-label`**: 버튼의 접근성 레이블 - **`children`** - `FieldButtonValue` 또는 `FieldButtonPlaceholder`로 구성 - 두 요소는 스타일만 다르며 접근성 트리에서는 숨겨집니다. 현재 값과 버튼을 눌렀을 때 일어날 동작을 `buttonProps["accessibility-label"]`로 설명하세요. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [selectedCity, setSelectedCity] = useState(""); function selectCity() { "background only"; setSelectedCity("서울"); } function clearCity() { "background only"; setSelectedCity(""); } return ( {selectedCity ? ( {selectedCity} ) : ( 도시를 선택해주세요 )} ); } ``` ### Clear Button `showClearButton`을 `true`로 설정하면 Clear Button이 표시됩니다. `clearButtonProps.bindtap`에서 소비처가 관리하는 선택 값을 지우세요. `FieldButton`이 `disabled` 또는 `readOnly` 상태이면 Clear Button은 표시되지 않습니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [value, setValue] = useState("판교동"); function selectValue() { "background only"; setValue("정자동"); } function clearValue() { "background only"; setValue(""); } return ( {value ? ( {value} ) : ( 동네를 선택해주세요 )} ); } ``` ### `FieldButtonValue` & `FieldButtonPlaceholder` `FieldButtonValue`와 `FieldButtonPlaceholder`는 `FieldButton`의 자식으로 넣는 Lynx `` 요소입니다. 두 요소는 스크린 리더가 중복해 읽지 않도록 접근성 트리에서 숨겨집니다. 현재 값과 버튼 동작은 `buttonProps["accessibility-label"]`로 함께 제공하세요. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [value, setValue] = useState(""); function toggleValue() { "background only"; setValue((current) => (current ? "" : "값 설정됨")); } return ( FieldButtonValue FieldButtonPlaceholder {value ? ( {value} ) : ( 탭하여 값 설정 )} ); } ``` ### Accessibility **Field Button 내부 버튼에 `accessibility-label`을 제공하세요.** 버튼을 눌렀을 때 어떤 선택 화면이 열리는지 설명하고, 현재 선택된 값이 있으면 그 값도 포함합니다. ```tsx {username ? ( {username} ) : ( 김하늘 )} ``` ### Use Cases #### Controlled State Lynx는 HTML Form을 지원하지 않습니다. 선택 값은 React state로 관리하고 `buttonProps.bindtap`에서 피커를 연 뒤 값을 갱신합니다. Clear Button은 `clearButtonProps.bindtap`에서 같은 state를 비웁니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [selectedCity, setSelectedCity] = useState(""); function selectCity() { "background only"; setSelectedCity("서울"); } function clearCity() { "background only"; setSelectedCity(""); } return ( {selectedCity ? ( {selectedCity} ) : ( 도시를 선택해주세요 )} ); } ``` #### Bottom Sheet or Picker `buttonProps.bindtap`에서 Bottom Sheet나 피커를 열고, 선택 결과를 `FieldButtonValue`로 렌더링하세요. Field Button은 어떤 선택 UI를 열지 정하지 않습니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { ActionButton, BottomSheet, useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [open, setOpen] = useState(false); const [value, setValue] = useState(""); function openPicker() { "background only"; setOpen(true); } function selectValue() { "background only"; setValue("판교동"); setOpen(false); } function clearValue() { "background only"; setValue(""); } return ( {value ? ( {value} ) : ( 동네를 선택해주세요 )} 동네 선택 거래할 동네를 선택해주세요. 판교동 선택 ); } ``` ### State #### Enabled ```tsx import "./styles"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); function handleTap() { "background only"; } return ( 플레이스홀더 플레이스홀더 ); } ``` #### Disabled `disabled` 상태에서는 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다. ```tsx import "./styles"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); function handleTap() { "background only"; } return ( 플레이스홀더 플레이스홀더 ); } ``` #### Read Only `readOnly` 상태에서는 현재 값을 표시하지만 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다. ```tsx import "./styles"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( 플레이스홀더 플레이스홀더 ); } ``` ### Size `size`로 Field Button의 크기를 정합니다. 기본값은 `large`입니다. Lynx에서는 `large`와 `medium`을 지원합니다. CSS viewport breakpoint가 없어 `responsive`는 지원하지 않습니다. ```tsx import "./styles"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( 플레이스홀더 플레이스홀더 ); } ``` ### Customizable Parts 아이콘만으로 의미를 전달하지 마세요. `label`, `description`, `buttonProps["accessibility-label"]`에 선택 대상과 현재 값을 텍스트로 설명합니다. #### Prefix ```tsx import "./styles"; import IconMagnifyingglassLine from "@karrotmarket/lynx-monochrome-icon/IconMagnifyingglassLine"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( example.com } buttonProps={{ "accessibility-label": "검색 조건 선택" }} > 검색 조건 ); } ``` #### Suffix ```tsx import "./styles"; import IconWonLine from "@karrotmarket/lynx-monochrome-icon/IconWonLine"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( 170 } buttonProps={{ "accessibility-label": "거래 금액 선택" }} > 50,000 ); } ``` #### Both Affixes ```tsx import "./styles"; import IconPlusCircleLine from "@karrotmarket/lynx-monochrome-icon/IconPlusCircleLine"; import IconWonLine from "@karrotmarket/lynx-monochrome-icon/IconWonLine"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( 25 } suffixIcon={} buttonProps={{ "accessibility-label": "추가 금액 선택" }} > 50,000 ); } ``` #### Indicator `indicator` 또는 `showRequiredIndicator`를 사용할 수 있습니다. 필수 항목에는 `required`도 함께 지정합니다. ```tsx import "./styles"; import { useSeedClassName, VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( 플레이스홀더 플레이스홀더 ); } ``` ## Web Version Differences 본문은 배경을 유지하고 콘텐츠만 축소하는 Content Scale을, ClearButton은 자체 영역을 축소하는 Root Scale을 적용합니다. Primitive를 직접 조합할 때는 Button을 Root의 직접 자식 또는 Fragment 안에 배치해야 본문 Content Scale이 연결됩니다. Button을 사용자 정의 컴포넌트로 감싸면 본문 Content Scale은 적용되지 않습니다. - HTML `