Action Button
명확한 액션을 쉽게 수행할 수 있도록 돕는 기본 인터랙션 컴포넌트입니다.
npm install @seed-design/lynx-react @seed-design/lynx-css
pnpm add @seed-design/lynx-react @seed-design/lynx-css
yarn add @seed-design/lynx-react @seed-design/lynx-css
bun add @seed-design/lynx-react @seed-design/lynx-css
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton>라벨</ActionButton>
</view>
</view>
);
}
icon?React.ReactElement<LynxIconElementProps, string | React.JSXElementConstructor<any>> | undefined
prefixIcon?React.ReactElement<LynxIconElementProps, string | React.JSXElementConstructor<any>> | undefined
suffixIcon?React.ReactElement<LynxIconElementProps, string | React.JSXElementConstructor<any>> | undefined
flexGrow?boolean | Property.FlexGrow | undefined
children?React.ReactNode
className?string | undefined
bindtap?EventHandler<BaseTouchEvent<Target>> | undefined
main-thread:bindtap?EventHandler<BaseTouchEvent<Element>> | undefined
accessibility-label?string | undefined
accessibility-element?boolean | undefined
accessibility-traits?"disabled" | "text" | "image" | "button" | "link" | "header" | "search" | "selected" | "playable" | "keyboard" | "summary" | "updating" | "adjustable" | "tabbar" | "none" | undefined
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="brandSolid">라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="neutralSolid">라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="neutralWeak">라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="criticalSolid">라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="brandOutline">라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="neutralOutline">라벨</ActionButton>
</view>
</view>
);
}
Lynx에서는 기본 Ghost 스타일을 지원합니다. 웹의 color, fontWeight 사용자 지정은 지원하지 않습니다.
import "./styles";
import IconTagFill from "@karrotmarket/lynx-monochrome-icon/IconTagFill";
import { ActionButton, PrefixIcon, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton variant="ghost">
<PrefixIcon icon={<IconTagFill />} />
Default (fg.neutral)
</ActionButton>
</view>
</view>
);
}
import "./styles";
import IconPlusFill from "@karrotmarket/lynx-monochrome-icon/IconPlusFill";
import { ActionButton, Icon, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton layout="iconOnly" accessibility-label="추가">
<Icon icon={<IconPlusFill />} />
</ActionButton>
</view>
</view>
);
}
import "./styles";
import IconPlusFill from "@karrotmarket/lynx-monochrome-icon/IconPlusFill";
import { ActionButton, PrefixIcon, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton>
<PrefixIcon icon={<IconPlusFill />} />
라벨
</ActionButton>
</view>
</view>
);
}
import "./styles";
import IconChevronRightFill from "@karrotmarket/lynx-monochrome-icon/IconChevronRightFill";
import { ActionButton, SuffixIcon, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton>
라벨
<SuffixIcon icon={<IconChevronRightFill />} />
</ActionButton>
</view>
</view>
);
}
import "./styles";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton disabled>라벨</ActionButton>
</view>
</view>
);
}
import "./styles";
import { useState } from "@lynx-js/react";
import { ActionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
const [loading, setLoading] = useState(false);
function handleTap() {
"background only";
setLoading(true);
setTimeout(() => setLoading(false), 2000);
}
return (
<view className={`${seedClassName} docs-lynx-action-button-root`}>
<view className="action-button-preview">
<ActionButton loading={loading} bindtap={handleTap}>
시간이 걸리는 액션
</ActionButton>
</view>
</view>
);
}
Lynx ActionButton은 React ActionButton과 다음과 같은 차이가 있습니다.
- 이벤트 핸들링:
onClick 대신 bindtap을 사용합니다.
- 렌더링 요소: HTML
<button> 대신 네이티브 <view>/<text> 요소를 렌더링합니다.
- 접근성 라벨링:
aria-label 대신 Lynx native accessibility-label을 사용합니다.
- ref forwarding:
React.forwardRef로 ref를 전달할 수 있습니다.
- 아이콘 렌더링 방식: 웹의 SVG
currentColor 대신 Lynx <image>의 tint-color를 사용합니다. Icon / PrefixIcon / SuffixIcon이 recipe color를 native tint로 동기화합니다.
- 호환 아이콘 prop: 기존
prefixIcon / suffixIcon / icon prop도 계속 지원하지만, 기본 예시는 child slot API를 사용합니다.
- Loading 상태: 두 플랫폼 모두 spinner를 absolute로 얹고 기존 content를 숨겨 원래 버튼 폭을 유지합니다. Lynx는 loading 중 tap을 막지만, 웹은 loading만으로
onClick을 막지 않습니다.
현재 Lynx 플랫폼 제약으로 다음 기능이 지원되지 않습니다.
| 기능 | 웹 대응 | 설명 |
|---|
color | StyleProps | CSS variable 동적 주입 제한 |
fontWeight | StyleProps | CSS variable 동적 주입 제한 |
bleed / bleedX / bleedY | StyleProps | CSS variable 동적 주입 제한 |
React 문서의 Bleed 예제는 Lynx에서 지원하지 않는 bleed, bleedX, bleedY를 사용하므로 Lynx Examples에서 제외했습니다.