# Field Button URL: /lynx/components/field-button Source: https://github.com/daangn/seed-design/blob/dev/docs/content/lynx/components/field-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 } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const [value, setValue] = useState(null); const selectValue = useCallback(() => { "background only"; setValue("판교동"); }, []); const changeValues = useCallback(([nextValue]: string[]) => { "background only"; setValue(nextValue ?? 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` 고유 prop이 없습니다. `className`, `style`, `children`을 받습니다. ### `FieldButtonPlaceholder` 고유 prop이 없습니다. `className`, `style`, `children`을 받습니다. ## Examples ### Basic Usage `FieldButton`은 값을 직접 편집하지 않고 선택창이나 피커를 여는 버튼입니다. `buttonProps.bindtap`에 열기 동작을 전달하고, 선택 여부에 따라 `FieldButtonValue` 또는 `FieldButtonPlaceholder`를 자식으로 사용합니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const [selectedCity, setSelectedCity] = useState(""); function selectCity() { "background only"; setSelectedCity("서울"); } function changeCities([nextCity = ""]: string[]) { "background only"; setSelectedCity(nextCity); } return ( {selectedCity ? ( {selectedCity} ) : ( 도시를 선택해주세요 )} ); } ``` ### Clear Button `showClearButton`을 `true`로 설정하면 Clear Button이 표시됩니다. 선택 값은 소비처가 `values`로 소유하고, Clear Button을 누르면 `clearButtonProps.bindtap` 다음에 `onValuesChange([])`가 호출됩니다. `onValuesChange`에서 소비처 state를 비우세요. Field Button은 값을 직접 바꾸지 않습니다. `FieldButton`이 `disabled` 또는 `readOnly` 상태이면 Clear Button은 표시되지 않습니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const [value, setValue] = useState("판교동"); function selectValue() { "background only"; setValue("정자동"); } function changeValues([nextValue = ""]: string[]) { "background only"; setValue(nextValue); } return ( {value ? ( {value} ) : ( 동네를 선택해주세요 )} ); } ``` ### `FieldButtonValue` & `FieldButtonPlaceholder` `FieldButtonValue`는 선택된 값을, `FieldButtonPlaceholder`는 값이 없을 때의 안내를 표시합니다. 두 요소의 텍스트는 스크린 리더가 중복해 읽지 않도록 접근성 트리에서 숨겨집니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { 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로 관리해 `values`로 전달하고, `buttonProps.bindtap`에서 피커를 연 뒤 값을 갱신합니다. Clear Button이 요청하는 빈 배열은 `onValuesChange`에서 같은 state에 반영합니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const [selectedCity, setSelectedCity] = useState(""); function selectCity() { "background only"; setSelectedCity("서울"); } function changeCities([nextCity = ""]: string[]) { "background only"; setSelectedCity(nextCity); } 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, VStack } from "@seed-design/lynx-react"; import { BottomSheetContent, BottomSheetFooter, BottomSheetRoot, } from "@/components/ui/bottom-sheet"; import { FieldButton, FieldButtonPlaceholder, FieldButtonValue, } from "@/components/ui/field-button"; export default function Example() { const [open, setOpen] = useState(false); const [value, setValue] = useState(""); function openPicker() { "background only"; setOpen(true); } function selectValue() { "background only"; setValue("판교동"); setOpen(false); } function changeValues([nextValue = ""]: string[]) { "background only"; setValue(nextValue); } return ( {value ? ( {value} ) : ( 동네를 선택해주세요 )} 판교동 선택 ); } ``` ### State #### Enabled ```tsx import "./styles"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { function handleTap() { "background only"; } return ( 플레이스홀더 플레이스홀더 ); } ``` #### Disabled `disabled` 상태에서는 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다. ```tsx import "./styles"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { function handleTap() { "background only"; } return ( 플레이스홀더 플레이스홀더 ); } ``` #### Read Only `readOnly` 상태에서는 현재 값을 표시하지만 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다. ```tsx import "./styles"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { return ( 플레이스홀더 플레이스홀더 ); } ``` ### Size `size`로 Field Button의 크기를 정합니다. 기본값은 `large`입니다. Lynx에서는 `large`와 `medium`을 지원합니다. CSS viewport breakpoint가 없어 `responsive`는 지원하지 않습니다. ```tsx import "./styles"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { return ( 플레이스홀더 플레이스홀더 ); } ``` ### Customizable Parts #### Prefix ```tsx import "./styles"; import IconMagnifyingglassLine from "@karrotmarket/lynx-monochrome-icon/IconMagnifyingglassLine"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { return ( example.com } buttonProps={{ "accessibility-label": "검색 조건 선택" }} > 검색 조건 ); } ``` #### Suffix ```tsx import "./styles"; import IconWonLine from "@karrotmarket/lynx-monochrome-icon/IconWonLine"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { 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 { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { return ( 25 } suffixIcon={} buttonProps={{ "accessibility-label": "추가 금액 선택" }} > 50,000 ); } ``` #### Indicator `indicator` 또는 `showRequiredIndicator`를 사용할 수 있습니다. 필수 항목에는 `required`도 함께 지정합니다. ```tsx import "./styles"; import { VStack } from "@seed-design/lynx-react"; import { FieldButton, FieldButtonPlaceholder } from "@/components/ui/field-button"; export default function Example() { return ( 플레이스홀더 플레이스홀더 ); } ``` ## Web Version Differences - HTML `