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
본문은 배경을 유지하고 콘텐츠만 축소하는 Content Scale을, ClearButton은 자체 영역을 축소하는 Root Scale을 적용합니다. Primitive를 직접 조합할 때는 Button을 Root의 직접 자식 또는 Fragment 안에 배치해야 본문 Content Scale이 연결됩니다. Button을 사용자 정의 컴포넌트로 감싸면 본문 Content Scale은 적용되지 않습니다.
- 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