# 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 - HTML `