Reaction 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 IconBellFill from "@karrotmarket/lynx-monochrome-icon/IconBellFill";
import { Count, PrefixIcon, ReactionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-reaction-button-root`}>
<view className="reaction-button-preview">
<ReactionButton>
<PrefixIcon icon={<IconBellFill />} />
도움돼요
<Count>1</Count>
</ReactionButton>
</view>
</view>
);
}
pressed?boolean | undefined
defaultPressed?boolean | undefined
onPressedChange?((pressed: boolean) => void) | undefined
disabled?boolean | undefined
loading?boolean | undefined
style?CSSProperties | undefined
children?React.ReactNode
className?string | undefined
bindtap?EventHandler<BaseTouchEvent<Target>> | undefined
main-thread:bindtap?EventHandler<BaseTouchEvent<Element>> | undefined
import "./styles";
import IconBellFill from "@karrotmarket/lynx-monochrome-icon/IconBellFill";
import { Count, PrefixIcon, ReactionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-reaction-button-root`}>
<view className="reaction-button-preview">
<ReactionButton size="small">
<PrefixIcon icon={<IconBellFill />} />
도움돼요
<Count>1</Count>
</ReactionButton>
</view>
</view>
);
}
import "./styles";
import IconBellFill from "@karrotmarket/lynx-monochrome-icon/IconBellFill";
import { Count, PrefixIcon, ReactionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-reaction-button-root`}>
<view className="reaction-button-preview">
<ReactionButton size="xsmall">
<PrefixIcon icon={<IconBellFill />} />
도움돼요
<Count>1</Count>
</ReactionButton>
</view>
</view>
);
}
import "./styles";
import IconBellFill from "@karrotmarket/lynx-monochrome-icon/IconBellFill";
import { PrefixIcon, ReactionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
return (
<view className={`${seedClassName} docs-lynx-reaction-button-root`}>
<view className="reaction-button-preview">
<ReactionButton disabled>
<PrefixIcon icon={<IconBellFill />} />
비활성
</ReactionButton>
</view>
</view>
);
}
import "./styles";
import IconBellFill from "@karrotmarket/lynx-monochrome-icon/IconBellFill";
import { useState } from "@lynx-js/react";
import { PrefixIcon, ReactionButton, useSeedClassName } from "@seed-design/lynx-react";
export default function Example() {
const seedClassName = useSeedClassName({ colorMode: "system" });
const [{ pressed, loading }, setState] = useState({
pressed: false,
loading: false,
});
function handleToggle() {
"background only";
setState((previous) => ({ pressed: previous.pressed, loading: true }));
setTimeout(() => {
setState((previous) => ({ pressed: !previous.pressed, loading: false }));
}, 2000);
}
return (
<view className={`${seedClassName} docs-lynx-reaction-button-root`}>
<view className="reaction-button-preview">
<ReactionButton loading={loading} pressed={pressed} onPressedChange={handleToggle}>
<PrefixIcon icon={<IconBellFill />} />
시간이 걸리는 토글
</ReactionButton>
</view>
</view>
);
}
Loading 중에도 bindtap과 onPressedChange가 동작합니다. 이벤트를 막아야 한다면 disabled를 함께 사용하세요.
Lynx ReactionButton은 React ReactionButton과 다음과 같은 차이가 있습니다.
- 이벤트 핸들링:
onClick 대신 bindtap을 사용합니다.
- 렌더링 요소: HTML
<button> 대신 네이티브 <view>와 <text> 요소를 렌더링합니다.
- 접근성 속성:
aria-* 대신 Lynx native accessibility-* 속성을 사용합니다.
- HTML 기능: button/form 속성, 키보드 focus,
asChild를 지원하지 않습니다.
- Loading 상태: spinner를 absolute로 얹고 기존 content를 숨겨 원래 버튼 폭을 유지합니다. React와 마찬가지로 이벤트는 유지됩니다.