플로팅 버튼
플로팅 버튼 (FloatButton)
사이트의 전역 기능에 쓰이는 부유하는 버튼이에요. 어디를 둘러보든 항상 보이는 동작 버튼이 필요할 때 사용해요.
출처: 문서
본문
언제 사용하나요 (When To Use)
- 사이트의 전역 기능에 사용해요.
- 어디를 둘러보든 볼 수 있는 버튼이 필요할 때 사용해요.
예시 (Examples)
기본 (Basic)
가장 기본적인 사용법이에요.
import React from 'react';
import { FloatButton } from 'antd';
const App: React.FC = () => <FloatButton onClick={() => console.log('onClick')} />;
export default App;
타입 (Type)
type 속성으로 FloatButton의 타입을 바꿔요.
import React from 'react';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton icon={<QuestionCircleOutlined />} type="primary" style={{ insetInlineEnd: 24 }} />
<FloatButton icon={<QuestionCircleOutlined />} type="default" style={{ insetInlineEnd: 94 }} />
</>
);
export default App;
모양 (Shape)
shape 속성으로 FloatButton의 모양을 바꿔요.
import React from 'react';
import { CustomerServiceOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton
shape="circle"
type="primary"
style={{ insetInlineEnd: 94 }}
icon={<CustomerServiceOutlined />}
/>
<FloatButton
shape="square"
type="primary"
style={{ insetInlineEnd: 24 }}
icon={<CustomerServiceOutlined />}
/>
</>
);
export default App;
콘텐츠 (Content)
content 속성을 설정하면 설명이 있는 FloatButton을 보여 줄 수 있어요.
shape가square일 때만 지원돼요. 텍스트 공간이 좁기 때문에 짧은 문장을 권장해요.
import React from 'react';
import { FileTextOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton
icon={<FileTextOutlined />}
content="HELP INFO"
shape="square"
style={{ insetInlineEnd: 24 }}
/>
<FloatButton content="HELP INFO" shape="square" style={{ insetInlineEnd: 94 }} />
<FloatButton
icon={<FileTextOutlined />}
content="HELP"
shape="square"
style={{ insetInlineEnd: 164 }}
/>
</>
);
export default App;
툴팁이 있는 FloatButton (FloatButton with tooltip)
tooltip 속성을 설정하면 툴팁이 있는 FloatButton을 보여 줘요.
import React from 'react';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton
style={{ insetBlockEnd: 108 }}
tooltip={{
// tooltipProps is supported starting from version 5.25.0.
title: 'Since 5.25.0+',
color: 'blue',
placement: 'top',
}}
/>
<FloatButton tooltip={<div>Documents</div>} />
</>
);
export default App;
FloatButton 그룹 (FloatButton Group)
여러 버튼을 함께 사용할 때는 <FloatButton.Group />을 권장해요. FloatButton.Group의 shape 속성을 설정하면 그룹의 모양을 바꿀 수 있어요. 그룹의 shape가 그룹 안의 FloatButton들의 shape보다 우선해요.
import React from 'react';
import { QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton.Group shape="circle" style={{ insetInlineEnd: 24 }}>
<FloatButton icon={<QuestionCircleOutlined />} />
<FloatButton />
<FloatButton.BackTop visibilityHeight={0} />
</FloatButton.Group>
<FloatButton.Group shape="square" style={{ insetInlineEnd: 94 }}>
<FloatButton icon={<QuestionCircleOutlined />} />
<FloatButton />
<FloatButton icon={<SyncOutlined />} />
<FloatButton.BackTop visibilityHeight={0} />
</FloatButton.Group>
</>
);
export default App;
메뉴 모드 (Menu mode)
trigger로 메뉴 모드를 엽니다. hover 또는 click이 될 수 있어요.
import React from 'react';
import { CommentOutlined, CustomerServiceOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton.Group
trigger="click"
type="primary"
style={{ insetInlineEnd: 24 }}
icon={<CustomerServiceOutlined />}
>
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
<FloatButton.Group
trigger="hover"
type="primary"
style={{ insetInlineEnd: 94 }}
icon={<CustomerServiceOutlined />}
>
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
</>
);
export default App;
제어 모드 (Controlled mode)
open으로 컴포넌트를 제어 모드로 설정해요. trigger와 함께 사용해야 해요.
import React, { useState } from 'react';
import { CommentOutlined, CustomerServiceOutlined } from '@ant-design/icons';
import { FloatButton, Switch } from 'antd';
const App: React.FC = () => {
const [open, setOpen] = useState<boolean>(true);
return (
<>
<Switch onChange={setOpen} checked={open} style={{ margin: 16 }} />
<FloatButton.Group
open={open}
trigger="click"
style={{ insetInlineEnd: 24 }}
icon={<CustomerServiceOutlined />}
>
<FloatButton />
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
<FloatButton.Group
open={open}
shape="square"
trigger="click"
style={{ insetInlineEnd: 88 }}
icon={<CustomerServiceOutlined />}
>
<FloatButton />
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
</>
);
};
export default App;
배치 (placement)
애니메이션 배치를 커스터마이즈할 수 있어요. top, right, bottom, left 네 가지 프리셋 배치를 제공하며 기본은 top이에요.
import React from 'react';
import {
CommentOutlined,
DownOutlined,
LeftOutlined,
RightOutlined,
UpOutlined,
} from '@ant-design/icons';
import { Flex, FloatButton } from 'antd';
const BOX_SIZE = 100;
const BUTTON_SIZE = 40;
const wrapperStyle: React.CSSProperties = {
width: '100%',
height: '100vh',
overflow: 'hidden',
position: 'relative',
};
const boxStyle: React.CSSProperties = {
width: BOX_SIZE,
height: BOX_SIZE,
position: 'relative',
};
const insetInlineEnd: React.CSSProperties['insetInlineEnd'][] = [
(BOX_SIZE - BUTTON_SIZE) / 2,
-(BUTTON_SIZE / 2),
(BOX_SIZE - BUTTON_SIZE) / 2,
BOX_SIZE - BUTTON_SIZE / 2,
];
const bottom: React.CSSProperties['bottom'][] = [
BOX_SIZE - BUTTON_SIZE / 2,
(BOX_SIZE - BUTTON_SIZE) / 2,
-BUTTON_SIZE / 2,
(BOX_SIZE - BUTTON_SIZE) / 2,
];
const icons = [
<UpOutlined key="up" />,
<RightOutlined key="right" />,
<DownOutlined key="down" />,
<LeftOutlined key="left" />,
];
const App: React.FC = () => (
<Flex justify="space-evenly" align="center" style={wrapperStyle}>
<div style={boxStyle}>
{(['top', 'right', 'bottom', 'left'] as const).map((placement, i) => {
const style: React.CSSProperties = {
position: 'absolute',
insetInlineEnd: insetInlineEnd[i],
bottom: bottom[i],
};
return (
<FloatButton.Group
key={placement}
trigger="click"
placement={placement}
style={style}
icon={icons[i]}
>
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
);
})}
</div>
</Flex>
);
export default App;
드래그 (draggable)
서드파티 라이브러리로 드래그 앤 드롭 기능을 구현해요.
import React from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext, PointerSensor, useDraggable, useSensor, useSensors } from '@dnd-kit/core';
import { CSS } from '@dnd-kit/utilities';
import { FloatButton } from 'antd';
interface Position {
x: number;
y: number;
}
interface DraggableButtonProps {
position: Position;
}
const DraggableButton: React.FC<DraggableButtonProps> = (props) => {
const { position } = props;
const { attributes, isDragging, listeners, setNodeRef, transform } = useDraggable({
id: 'draggable-float-button',
});
const mergedTransform = CSS.Translate.toString({
x: position.x + (transform?.x ?? 0),
y: position.y + (transform?.y ?? 0),
scaleX: transform?.scaleX ?? 1,
scaleY: transform?.scaleY ?? 1,
});
return (
<FloatButton
ref={setNodeRef}
{...listeners}
{...attributes}
style={{
transform: mergedTransform,
cursor: isDragging ? 'grabbing' : 'grab',
transition: isDragging ? 'none' : undefined,
touchAction: 'none',
}}
/>
);
};
const Demo: React.FC = () => {
const [position, setPosition] = React.useState<Position>({ x: 0, y: 0 });
const sensor = useSensor(PointerSensor, {
activationConstraint: {
distance: 10,
},
});
const sensors = useSensors(sensor);
const onDragEnd = (event: DragEndEvent) => {
const { delta } = event;
setPosition(({ x, y }) => ({ x: x + delta.x, y: y + delta.y }));
};
return (
<DndContext sensors={sensors} onDragEnd={onDragEnd} id="float-button-draggable">
<DraggableButton position={position} />
</DndContext>
);
};
export default Demo;
BackTop
BackTop은 페이지 맨 위로 쉽게 돌아갈 수 있게 해 줘요.
import React from 'react';
import { FloatButton } from 'antd';
const Demo: React.FC = () => {
return (
<div style={{ height: '300vh', padding: 10 }}>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<FloatButton.BackTop style={{ insetInlineEnd: 24 }} shape="circle" />
<FloatButton.BackTop style={{ insetInlineEnd: 88 }} shape="square" />
</div>
);
};
export default Demo;
진행률 링 (Progress ring)
showProgress를 사용해 BackTop 버튼 가장자리에 현재 스크롤 진행률을 표시해요.
import React from 'react';
import { FloatButton } from 'antd';
const sharedProps: React.ComponentProps<typeof FloatButton.BackTop> = {
showProgress: true,
visibilityHeight: 0,
};
const Demo: React.FC = () => {
return (
<div style={{ height: '300vh', padding: 10 }}>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<FloatButton.BackTop {...sharedProps} style={{ insetInlineEnd: 24 }} shape="circle" />
<FloatButton.BackTop {...sharedProps} style={{ insetInlineEnd: 88 }} shape="square" />
</div>
);
};
export default Demo;
배지 (badge)
Badge가 있는 FloatButton이에요.
import React from 'react';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
const App: React.FC = () => (
<>
<FloatButton shape="circle" style={{ insetInlineEnd: 24 + 70 + 70 }} badge={{ dot: true }} />
<FloatButton.Group shape="circle" style={{ insetInlineEnd: 24 + 70 }}>
<FloatButton tooltip={<div>custom badge color</div>} badge={{ count: 5, color: 'blue' }} />
<FloatButton badge={{ count: 5 }} />
</FloatButton.Group>
<FloatButton.Group shape="circle">
<FloatButton badge={{ count: 12 }} icon={<QuestionCircleOutlined />} />
<FloatButton badge={{ count: 123, overflowCount: 999 }} />
<FloatButton.BackTop visibilityHeight={0} />
</FloatButton.Group>
</>
);
export default App;
시맨틱 DOM 스타일링 (Custom semantic dom styling)
classNames와 styles로 객체나 함수를 전달해 FloatButton의 시맨틱 DOM 스타일을 커스터마이즈할 수 있어요.
import React from 'react';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { FloatButton } from 'antd';
import type { FloatButtonProps, GetProp } from 'antd';
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => ({
root: {
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
borderRadius: token.borderRadius,
padding: `${token.paddingXS}px ${token.padding}px`,
height: 'auto',
},
content: {
color: token.colorText,
},
}));
const stylesObject: FloatButtonProps['styles'] = {
root: {
boxShadow: '0 1px 2px 0 rgba(0,0,0,0.05)',
},
};
const stylesFn: FloatButtonProps['styles'] = (
info,
): GetProp<FloatButtonProps, 'styles', 'Return'> => {
if (info.props.type === 'primary') {
return {
root: {
backgroundColor: '#171717',
},
content: {
color: '#fff',
},
};
}
};
const App: React.FC = () => {
const { styles: classNames } = useStyles();
return (
<FloatButton.Group shape="circle" style={{ insetInlineEnd: 24 + 70 }}>
<FloatButton
type="primary"
classNames={classNames}
styles={stylesFn}
tooltip={<div>custom style class</div>}
/>
<FloatButton
type="default"
classNames={classNames}
styles={stylesObject}
icon={<QuestionCircleOutlined />}
/>
</FloatButton.Group>
);
};
export default App;
API
공통 props는 Common props를 참고해요.
이 컴포넌트는
[email protected]부터 사용할 수 있어요.
공통 API (common API)
| 속성 (Property) | 설명 (Description) | 타입 (Type) | 기본값 (Default) | 버전 (Version) | 글로벌 설정 |
|---|---|---|---|---|---|
| icon | 버튼의 아이콘 컴포넌트를 설정해요. | ReactNode | - | FloatButton: ×, BackTop: 5.27.0 | |
| classNames | 컴포넌트 내부의 각 시맨틱 구조에 대한 class를 지정해요. 객체 또는 함수를 지원해요. | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | 6.0.0 | |
| content | 텍스트 및 기타 | ReactNode | - | × | |
content를 대신 사용해 주세요. |
ReactNode | - | × | ||
| tooltip | 툴팁에 표시되는 텍스트 | ReactNode | TooltipProps | - | TooltipProps: 5.25.0 | × |
| type | 버튼 타입 설정 | default | primary |
default |
× | |
| shape | 버튼 모양 설정 | circle | square |
circle |
× | |
| styles | 컴포넌트 내부의 각 시맨틱 구조에 대한 인라인 스타일을 지정해요. 객체 또는 함수를 지원해요. | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | 6.0.0 | |
| onClick | click 이벤트 처리 핸들러를 설정해요. |
(event) => void | - | × | |
| href | 하이퍼링크의 대상 | string | - | × | |
| target | 연결된 URL을 어디에 표시할지 지정해요. | string | - | × | |
| htmlType | button의 원래 html type을 설정해요. MDN 참고. |
submit | reset | button |
button |
5.21.0 | × |
| badge | FloatButton에 Badge를 부착해요. status 및 관련 props는 지원하지 않아요. |
BadgeProps | - | 5.4.0 | × |
| disabled | 버튼 비활성화 여부 | boolean | - | 6.4.0 | × |
FloatButton.Group
| 속성 (Property) | 설명 (Description) | 타입 (Type) | 기본값 (Default) | 버전 (Version) | 글로벌 설정 |
|---|---|---|---|---|---|
| open | 메뉴가 보이는지 여부예요. trigger와 함께 사용해요. | boolean | - | × | |
| closeIcon | 닫기 버튼 아이콘 커스터마이즈 | React.ReactNode | <CloseOutlined /> |
5.16.0 | |
| placement | 메뉴 애니메이션 배치 커스터마이즈 | top | left | right | bottom |
top |
5.21.0 | × |
| shape | 자식 버튼의 모양 설정 | circle | square |
circle |
× | |
| trigger | 메뉴 열기/닫기를 트리거하는 동작 | click | hover |
- | × | |
| onOpenChange | 활성 메뉴가 변경될 때 실행되는 콜백. trigger와 함께 사용해요. | (open: boolean) => void | - | × | |
| onClick | click 이벤트 처리 핸들러 (메뉴 모드에서만 동작해요.) |
(event) => void | - | 5.3.0 | × |
FloatButton.BackTop
| 속성 (Property) | 설명 (Description) | 타입 (Type) | 기본값 (Default) | 버전 (Version) |
|---|---|---|---|---|
| duration | 맨 위로 돌아가는 시간(ms)이에요. 축소 모션(prefers-reduced-motion: reduce)이 활성화되면 무시돼요. |
number | 450 | |
| showProgress | BackTop 버튼 가장자리에 현재 스크롤 진행률 링을 표시해요. | boolean | false | 6.6.0 |
| target | 스크롤 가능한 영역 dom 노드를 지정해요. | () => HTMLElement | () => window | |
| visibilityHeight | 스크롤 높이가 이 값에 도달하기 전까지 BackTop 버튼을 표시하지 않아요. | number | 400 | |
| onClick | 버튼을 클릭할 때 실행되는 콜백 함수 | () => void | - |
시맨틱 DOM (Semantic DOM)
FloatButton
시맨틱 DOM 구조는 https://ant.design/components/float-button/semantic.md 에서 확인할 수 있어요.
FloatButton.Group
시맨틱 DOM 구조는 https://ant.design/components/float-button/semantic_group.md 에서 확인할 수 있어요.
디자인 토큰 (Design Token)
글로벌 토큰 (Global Token)
| 토큰 이름 (Token Name) | 설명 (Description) | 타입 (Type) | 기본값 (Default Value) |
|---|---|---|---|
| borderRadius | 기본 컴포넌트의 테두리 반경 | number | |
| borderRadiusLG | LG 크기 테두리 반경이에요. Card, Modal 등 큰 테두리 반경을 가진 컴포넌트에 사용돼요. | number | |
| boxShadowSecondary | 요소의 2차 박스 섀도우 스타일을 제어해요. | string | |
| colorBorderSecondary | 기본 테두리 색보다 약간 밝으며 colorSplit과 같은 색이에요. 단색이 사용돼요. |
string | |
| colorPrimary | 브랜드 색은 제품의 특성과 커뮤니케이션을 반영하는 가장 직접적인 시각 요소 중 하나예요. 브랜드 색을 선택하면 자동으로 완전한 색 팔레트가 생성되고 유효한 디자인 시맨틱이 부여돼요. | string | |
| colorText | W3C 표준을 따르는 기본 텍스트 색이에요. 가장 어두운 중성색이기도 해요. | string | |
| controlHeight | Ant Design에서 버튼, 입력 상자 같은 기본 컨트롤의 높이 | number | |
| controlHeightLG | LG 컴포넌트 높이 | number | |
| fontFamily | Ant Design의 글꼴은 시스템의 기본 인터페이스 글꼴을 우선시하고, 화면 표시에 적합한 대체 글꼴 라이브러리를 제공해 플랫폼과 브라우저에 따라 가독성을 유지하며 친근하고 안정적이며 전문적인 특성을 반영해요. | string | |
| fontSize | 디자인 시스템에서 가장 널리 쓰이는 글자 크기로, 여기서 텍스트 그라데이션이 파생돼요. | number | |
| fontSizeIcon | Select, Cascader 등의 동작 아이콘 글자 크기를 제어해요. 보통 fontSizeSM과 같아요. | number | |
| fontSizeSM | 작은 글자 크기 | number | |
| lineHeight | 텍스트의 줄 높이예요. | number | |
| lineWidthBold | Button, Input, Select 등 outline 계열 컴포넌트의 기본 선 너비 | number | |
| marginLG | 큰 크기의 요소 여백을 제어해요. | number | |
| marginXXL | 가장 큰 크기의 요소 여백을 제어해요. | number | |
| motionDurationMid | 동작 속도, 중간 속도예요. 중간 요소의 애니메이션 상호작용에 사용돼요. | string | |
| motionDurationSlow | 동작 속도, 느린 속도예요. 큰 요소의 애니메이션 상호작용에 사용돼요. | string | |
| padding | 요소의 패딩을 제어해요. | number | |
| paddingXXS | 요소의 아주 작은 패딩을 제어해요. | number | |
| zIndexPopupBase | FloatButton, Affix처럼 큰 팝업에 덮일 수 있는 컴포넌트의 기본 zIndex | number |