플로팅 버튼

플로팅 버튼 (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 - ×
description 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

더 알아보기 (Learn more)