Field Button
입력 필드 형태의 버튼으로, 선택창이나 피커를 열 때 사용합니다. 선택이 완료되면 버튼 라벨에 선택된 값이 표시됩니다.
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<string | null>(null);
const selectValue = useCallback(() => {
"background only";
setValue("판교동");
}, []);
const clearValue = useCallback(() => {
"background only";
setValue(null);
}, []);
return (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content">
<FieldButton
label="동네"
description="거래할 동네를 선택해 주세요."
showClearButton={value != null}
buttonProps={{
"accessibility-label": value ? `동네 변경. 현재: ${value}` : "동네 선택",
bindtap: selectValue,
}}
clearButtonProps={{
bindtap: clearValue,
}}
>
{value == null ? (
<FieldButtonPlaceholder>동네를 선택해 주세요</FieldButtonPlaceholder>
) : (
<FieldButtonValue>{value}</FieldButtonValue>
)}
</FieldButton>
</VStack>
</VStack>
</view>
);
}Installation
npx @seed-design/cli@latest add ui:field-buttonpnpm dlx @seed-design/cli@latest add ui:field-buttonyarn dlx @seed-design/cli@latest add ui:field-buttonbun x @seed-design/cli@latest add ui:field-button의존성 설치
npm install @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactyarn add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactpnpm add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactbun add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react아래 코드를 복사 후 붙여넣고 사용하세요
/**
* @file ui:field-button
* @requires @seed-design/lynx-react@>=0.7.0 <1.0.0
* @requires @seed-design/lynx-css@>=0.11.0 <1.0.0
* @requires @karrotmarket/lynx-monochrome-icon@>=1.20.0 <2.0.0
**/
import IconXmarkCircleFill from "@karrotmarket/lynx-monochrome-icon/IconXmarkCircleFill";
import * as React from "@lynx-js/react";
import { Field as SeedField, InputButton as SeedInputButton } from "@seed-design/lynx-react";
interface FieldButtonClearButtonProps extends Omit<SeedInputButton.ClearButtonProps, "icon"> {}
export interface FieldButtonProps extends Omit<SeedInputButton.RootProps, "children"> {
children?: React.ReactNode;
label?: React.ReactNode;
labelWeight?: SeedField.LabelProps["weight"];
indicator?: React.ReactNode;
prefixIcon?: SeedInputButton.PrefixIconProps["icon"];
prefix?: React.ReactNode;
suffixIcon?: SeedInputButton.SuffixIconProps["icon"];
suffix?: React.ReactNode;
description?: React.ReactNode;
errorMessage?: React.ReactNode;
required?: boolean;
showRequiredIndicator?: boolean;
showClearButton?: boolean;
buttonProps?: SeedInputButton.ButtonProps;
clearButtonProps?: FieldButtonClearButtonProps;
fieldRef?: React.Ref<React.ComponentRef<typeof SeedField.Root>>;
inputButtonRef?: React.Ref<React.ComponentRef<typeof SeedInputButton.Root>>;
}
/**
* @see https://seed-design.io/lynx/components/input-button
*/
export const FieldButton = React.forwardRef<unknown, FieldButtonProps>((props, ref) => {
const {
children,
label,
labelWeight,
indicator,
prefixIcon,
prefix,
suffixIcon,
suffix,
description,
errorMessage,
required,
showRequiredIndicator,
showClearButton,
buttonProps,
clearButtonProps,
fieldRef,
inputButtonRef,
disabled,
invalid,
readOnly,
...rootProps
} = props;
const renderHeader = label != null || indicator != null;
const renderDescription = description != null && !(invalid && errorMessage != null);
const renderErrorMessage = invalid && errorMessage != null;
const renderFooter = renderDescription || renderErrorMessage;
const renderClearButton = showClearButton && !disabled && !readOnly;
if (process.env.NODE_ENV !== "production" && !buttonProps?.["accessibility-label"]) {
console.warn("FieldButton: `buttonProps.accessibility-label` should be provided.");
}
return (
<SeedField.Root
ref={fieldRef}
required={required}
disabled={disabled}
invalid={invalid}
readOnly={readOnly}
>
{renderHeader ? (
<SeedField.Header>
<SeedField.Label weight={labelWeight}>
{label}
{showRequiredIndicator ? <SeedField.RequiredIndicator /> : null}
{indicator != null ? (
<SeedField.IndicatorText>{indicator}</SeedField.IndicatorText>
) : null}
</SeedField.Label>
</SeedField.Header>
) : null}
<SeedInputButton.Root
ref={inputButtonRef}
disabled={disabled}
invalid={invalid}
readOnly={readOnly}
{...rootProps}
>
<SeedInputButton.Button ref={ref} {...buttonProps} />
{prefixIcon ? <SeedInputButton.PrefixIcon icon={prefixIcon} /> : null}
{prefix != null ? <SeedInputButton.PrefixText>{prefix}</SeedInputButton.PrefixText> : null}
{children}
{renderClearButton ? (
<SeedInputButton.ClearButton
// 소비처에서 서비스 언어에 맞는 레이블로 재정의할 수 있습니다.
accessibility-label="지우기"
icon={<IconXmarkCircleFill />}
{...clearButtonProps}
/>
) : null}
{suffix != null ? <SeedInputButton.SuffixText>{suffix}</SeedInputButton.SuffixText> : null}
{suffixIcon ? <SeedInputButton.SuffixIcon icon={suffixIcon} /> : null}
</SeedInputButton.Root>
{renderFooter ? (
<SeedField.Footer>
{renderDescription ? <SeedField.Description>{description}</SeedField.Description> : null}
{renderErrorMessage ? (
<SeedField.ErrorMessage>{errorMessage}</SeedField.ErrorMessage>
) : null}
</SeedField.Footer>
) : null}
</SeedField.Root>
);
});
FieldButton.displayName = "FieldButton";
export interface FieldButtonValueProps extends SeedInputButton.ValueProps {}
/**
* @see https://seed-design.io/lynx/components/input-button
*/
export const FieldButtonValue = SeedInputButton.Value;
export interface FieldButtonPlaceholderProps extends SeedInputButton.PlaceholderProps {}
/**
* @see https://seed-design.io/lynx/components/input-button
*/
export const FieldButtonPlaceholder = SeedInputButton.Placeholder;
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
Props
FieldButton
Prop
Type
children?React.ReactNodelabel?React.ReactNodelabelWeight?"medium" | "bold" | undefinedindicator?React.ReactNodeprefixIcon?React.ReactElement<LynxIconElementProps, string | React.JSXElementConstructor<any>> | undefinedprefix?React.ReactNodesuffixIcon?React.ReactElement<LynxIconElementProps, string | React.JSXElementConstructor<any>> | undefinedsuffix?React.ReactNodedescription?React.ReactNodeerrorMessage?React.ReactNoderequired?boolean | undefinedshowRequiredIndicator?boolean | undefinedshowClearButton?boolean | undefinedbuttonProps?SeedInputButton.ButtonProps | undefinedclearButtonProps?FieldButtonClearButtonProps | undefinedfieldRef?React.Ref<NodesRef> | undefinedinputButtonRef?React.Ref<NodesRef> | undefinedstyle?CSSProperties | undefinedclassName?string | undefinedFieldButtonValue
Prop
Type
style?CSSProperties | undefinedchildren?React.ReactNodeclassName?string | undefinedFieldButtonPlaceholder
Prop
Type
style?CSSProperties | undefinedchildren?React.ReactNodeclassName?string | undefinedExamples
Basic Usage
FieldButton은 TextField와 유사한 외관을 갖지만, 값을 직접 편집하지 않고 선택창이나 피커를 여는 버튼입니다.
buttonPropsbindtap: 버튼 tap handleraccessibility-label: 버튼의 접근성 레이블
childrenFieldButtonValue또는FieldButtonPlaceholder로 구성- 두 요소는 스타일만 다르며 접근성 트리에서는 숨겨집니다. 현재 값과 버튼을 눌렀을 때 일어날 동작을
buttonProps["accessibility-label"]로 설명하세요.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content">
<FieldButton
label="도시"
showClearButton={selectedCity !== ""}
buttonProps={{
bindtap: selectCity,
"accessibility-label": selectedCity
? `도시 변경. 현재: ${selectedCity}`
: "도시 선택",
}}
clearButtonProps={{ bindtap: clearCity }}
>
{selectedCity ? (
<FieldButtonValue>{selectedCity}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>도시를 선택해주세요</FieldButtonPlaceholder>
)}
</FieldButton>
</VStack>
</VStack>
</view>
);
}Clear Button
showClearButton을 true로 설정하면 Clear Button이 표시됩니다. clearButtonProps.bindtap에서 소비처가 관리하는 선택 값을 지우세요.
FieldButton이 disabled 또는 readOnly 상태이면 Clear Button은 표시되지 않습니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content">
<FieldButton
label="동네"
showClearButton={value !== ""}
buttonProps={{
bindtap: selectValue,
"accessibility-label": `동네 선택.${value ? ` 현재 동네는 ${value}입니다.` : ""}`,
}}
clearButtonProps={{ bindtap: clearValue }}
>
{value ? (
<FieldButtonValue>{value}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>동네를 선택해주세요</FieldButtonPlaceholder>
)}
</FieldButton>
</VStack>
</VStack>
</view>
);
}FieldButtonValue & FieldButtonPlaceholder
FieldButtonValue와 FieldButtonPlaceholder는 FieldButton의 자식으로 넣는 Lynx <text> 요소입니다. 두 요소는 스크린 리더가 중복해 읽지 않도록 접근성 트리에서 숨겨집니다.
현재 값과 버튼 동작은 buttonProps["accessibility-label"]로 함께 제공하세요.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton buttonProps={{ "accessibility-label": "현재 값: FieldButtonValue" }}>
<FieldButtonValue>FieldButtonValue</FieldButtonValue>
</FieldButton>
<FieldButton buttonProps={{ "accessibility-label": "현재 값 없음" }}>
<FieldButtonPlaceholder>FieldButtonPlaceholder</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
buttonProps={{
bindtap: toggleValue,
"accessibility-label": value ? `값 지우기. 현재: ${value}` : "값 설정",
}}
>
{value ? (
<FieldButtonValue>{value}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>탭하여 값 설정</FieldButtonPlaceholder>
)}
</FieldButton>
</VStack>
</VStack>
</view>
);
}Accessibility
Field Button 내부 버튼에 accessibility-label을 제공하세요. 버튼을 눌렀을 때 어떤 선택 화면이 열리는지 설명하고, 현재 선택된 값이 있으면 그 값도 포함합니다.
<FieldButton
label="사용자 이름"
description="본명을 사용하지 않아도 괜찮습니다."
buttonProps={{
"accessibility-label": `사용자 이름 선택 화면 열기. 현재 선택된 이름: ${username || "없음"}`,
bindtap: openUsernamePicker,
}}
>
{username ? (
<FieldButtonValue>{username}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>김하늘</FieldButtonPlaceholder>
)}
</FieldButton>Use Cases
Controlled State
Lynx는 HTML Form을 지원하지 않습니다. 선택 값은 React state로 관리하고 buttonProps.bindtap에서 피커를 연 뒤 값을 갱신합니다. Clear Button은 clearButtonProps.bindtap에서 같은 state를 비웁니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content">
<FieldButton
label="도시"
showClearButton={selectedCity !== ""}
buttonProps={{
bindtap: selectCity,
"accessibility-label": selectedCity
? `도시 변경. 현재: ${selectedCity}`
: "도시 선택",
}}
clearButtonProps={{ bindtap: clearCity }}
>
{selectedCity ? (
<FieldButtonValue>{selectedCity}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>도시를 선택해주세요</FieldButtonPlaceholder>
)}
</FieldButton>
</VStack>
</VStack>
</view>
);
}Bottom Sheet or Picker
buttonProps.bindtap에서 Bottom Sheet나 피커를 열고, 선택 결과를 FieldButtonValue로 렌더링하세요. Field Button은 어떤 선택 UI를 열지 정하지 않습니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content">
<FieldButton
label="동네"
showClearButton={value !== ""}
buttonProps={{
bindtap: openPicker,
"accessibility-label": value ? `동네 변경. 현재: ${value}` : "동네 선택",
}}
clearButtonProps={{ bindtap: clearValue }}
>
{value ? (
<FieldButtonValue>{value}</FieldButtonValue>
) : (
<FieldButtonPlaceholder>동네를 선택해주세요</FieldButtonPlaceholder>
)}
</FieldButton>
</VStack>
</VStack>
<BottomSheet.Root open={open} onOpenChange={setOpen}>
<BottomSheet.Positioner>
<BottomSheet.Backdrop />
<BottomSheet.Content>
<BottomSheet.Header>
<BottomSheet.Title>동네 선택</BottomSheet.Title>
<BottomSheet.Description>거래할 동네를 선택해주세요.</BottomSheet.Description>
</BottomSheet.Header>
<BottomSheet.Footer>
<ActionButton variant="neutralSolid" bindtap={selectValue}>
판교동 선택
</ActionButton>
</BottomSheet.Footer>
</BottomSheet.Content>
</BottomSheet.Positioner>
</BottomSheet.Root>
</view>
);
}State
Enabled
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="라벨"
description="설명을 써주세요"
buttonProps={{ bindtap: handleTap, "accessibility-label": "값 선택" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="라벨"
invalid
errorMessage="오류가 발생한 이유를 써주세요"
buttonProps={{ bindtap: handleTap, "accessibility-label": "값 다시 선택" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Disabled
disabled 상태에서는 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="라벨"
description="설명을 써주세요"
disabled
showClearButton
buttonProps={{ bindtap: handleTap, "accessibility-label": "값 선택" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="라벨"
disabled
invalid
errorMessage="오류가 발생한 이유를 써주세요"
buttonProps={{ bindtap: handleTap, "accessibility-label": "값 선택" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Read Only
readOnly 상태에서는 현재 값을 표시하지만 버튼 tap handler가 실행되지 않고 Clear Button도 렌더링되지 않습니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="라벨"
description="설명을 써주세요"
readOnly
showClearButton
buttonProps={{ "accessibility-label": "현재 값: 플레이스홀더" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="라벨"
readOnly
invalid
errorMessage="오류가 발생한 이유를 써주세요"
buttonProps={{ "accessibility-label": "현재 값: 플레이스홀더" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Size
size로 Field Button의 크기를 정합니다. 기본값은 large입니다.
Lynx에서는 large와 medium을 지원합니다. CSS viewport breakpoint가 없어 responsive는 지원하지 않습니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="라벨"
description="size=large (default)"
size="large"
buttonProps={{ "accessibility-label": "큰 크기 선택 화면 열기" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="라벨"
description="size=medium"
size="medium"
buttonProps={{ "accessibility-label": "중간 크기 선택 화면 열기" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Customizable Parts
아이콘만으로 의미를 전달하지 마세요. label, description, buttonProps["accessibility-label"]에 선택 대상과 현재 값을 텍스트로 설명합니다.
Prefix
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="주소"
description="사이트 주소를 선택해주세요."
prefix="https://"
buttonProps={{ "accessibility-label": "사이트 주소 선택" }}
>
<FieldButtonPlaceholder>example.com</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="검색"
description="검색 조건을 선택해주세요."
prefixIcon={<IconMagnifyingglassLine />}
buttonProps={{ "accessibility-label": "검색 조건 선택" }}
>
<FieldButtonPlaceholder>검색 조건</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Suffix
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="키"
description="측정한 키를 선택해주세요."
suffix="cm"
buttonProps={{ "accessibility-label": "키 선택" }}
>
<FieldButtonPlaceholder>170</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="금액"
description="거래 금액을 선택해주세요."
suffixIcon={<IconWonLine />}
buttonProps={{ "accessibility-label": "거래 금액 선택" }}
>
<FieldButtonPlaceholder>50,000</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Both Affixes
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="나이"
description="나이를 선택해주세요."
prefix="만"
suffix="세"
buttonProps={{ "accessibility-label": "나이 선택" }}
>
<FieldButtonPlaceholder>25</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="추가 금액"
description="추가할 금액을 선택해주세요."
prefixIcon={<IconPlusCircleLine />}
suffixIcon={<IconWonLine />}
buttonProps={{ "accessibility-label": "추가 금액 선택" }}
>
<FieldButtonPlaceholder>50,000</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Indicator
indicator 또는 showRequiredIndicator를 사용할 수 있습니다. 필수 항목에는 required도 함께 지정합니다.
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 (
<view className={`${seedClassName} docs-lynx-input-button-root`}>
<VStack className="input-button-preview">
<VStack className="input-button-preview__content" gap="spacingY.componentDefault">
<FieldButton
label="선택 필드"
labelWeight="bold"
indicator="선택"
description="이 필드는 선택사항입니다."
buttonProps={{ "accessibility-label": "선택 값 입력" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
<FieldButton
label="필수 필드"
required
showRequiredIndicator
description="이 필드는 필수사항입니다."
buttonProps={{ "accessibility-label": "필수 값 입력" }}
>
<FieldButtonPlaceholder>플레이스홀더</FieldButtonPlaceholder>
</FieldButton>
</VStack>
</VStack>
</view>
);
}Web Version Differences
- HTML
<button>대신 Lynx<view>에 tap handler와accessibility-*속성을 적용합니다. onClick대신buttonProps.bindtap을 사용합니다. main thread handler가 필요하면buttonProps["main-thread:bindtap"]을 사용할 수 있습니다.aria-label대신buttonProps["accessibility-label"]을 사용합니다.- 선택 값은
values와onValuesChange대신 소비처의 React state로 관리합니다. size="responsive"는 지원하지 않습니다.large또는medium을 지정합니다.
Unsupported Lynx Features
- HTML form submit과 hidden input, browser validation, React Hook Form 연동은 지원하지 않습니다.
- DOM id 기반
aria-describedby연결과aria-haspopup은 지원하지 않습니다.
Last updated on