드롭다운
드롭다운 (Dropdown)
여러 옵션 중 하나를 선택할 때 사용하는 컴포넌트예요. 트리거를 호버하거나 클릭하면 메뉴가 나타나 옵션을 선택하고 관련 동작을 실행할 수 있어요.
출처: 문서
본문
언제 사용하나요 (When To Use)
선택할 옵션이 몇 개 이상일 때 Dropdown으로 감쌀 수 있어요. 트리거를 호버하거나 클릭하면 드롭다운 메뉴가 나타나고, 옵션을 선택해 관련 동작을 실행할 수 있어요.
예시 (Examples)
기본 (Basic)
가장 기본적인 드롭다운 메뉴예요.
import React from 'react';
import { DownOutlined, SmileOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
},
{
key: '2',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item (disabled)
</a>
),
icon: <SmileOutlined />,
disabled: true,
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item (disabled)
</a>
),
disabled: true,
},
{
key: '4',
danger: true,
label: 'a danger item',
},
];
const App: React.FC = () => (
<Dropdown menu={{ items }}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
export default App;
추가 노드 (Extra node)
단축키가 있는 드롭다운 메뉴예요.
import React from 'react';
import { DownOutlined, SettingOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: 'My Account',
disabled: true,
},
{
type: 'divider',
},
{
key: '2',
label: 'Profile',
extra: '⌘P',
},
{
key: '3',
label: 'Billing',
extra: '⌘B',
},
{
key: '4',
label: 'Settings',
icon: <SettingOutlined />,
extra: '⌘S',
},
];
const App: React.FC = () => (
<Dropdown menu={{ items }}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
export default App;
위치 (Placement)
12가지 위치를 지원해요.
import React from 'react';
import type { MenuProps } from 'antd';
import { Button, Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
},
{
key: '2',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
),
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
),
},
];
const App: React.FC = () => (
<Space vertical>
<Space wrap>
<Dropdown menu={{ items }} placement="bottomLeft">
<Button>bottomLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottom">
<Button>bottom</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottomRight">
<Button>bottomRight</Button>
</Dropdown>
</Space>
<Space wrap>
<Dropdown menu={{ items }} placement="topLeft">
<Button>topLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="top">
<Button>top</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="topRight">
<Button>topRight</Button>
</Dropdown>
</Space>
<Space wrap>
<Dropdown menu={{ items }} placement="leftTop">
<Button>leftTop</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="left">
<Button>left</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="leftBottom">
<Button>leftBottom</Button>
</Dropdown>
</Space>
<Space wrap>
<Dropdown menu={{ items }} placement="rightTop">
<Button>rightTop</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="right">
<Button>right</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="rightBottom">
<Button>rightBottom</Button>
</Dropdown>
</Space>
</Space>
);
export default App;
화살표 (Arrow)
화살표를 표시할 수 있어요.
import React from 'react';
import type { MenuProps } from 'antd';
import { Button, Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
},
{
key: '2',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
),
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
),
},
];
const App: React.FC = () => (
<Space vertical>
<Space wrap>
<Dropdown menu={{ items }} placement="bottomLeft" arrow>
<Button>bottomLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottom" arrow>
<Button>bottom</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottomRight" arrow>
<Button>bottomRight</Button>
</Dropdown>
</Space>
<Space wrap>
<Dropdown menu={{ items }} placement="topLeft" arrow>
<Button>topLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="top" arrow>
<Button>top</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="topRight" arrow>
<Button>topRight</Button>
</Dropdown>
</Space>
</Space>
);
export default App;
다른 요소 (Other elements)
구분선과 비활성화된 메뉴 항목이에요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
key: '0',
},
{
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
),
key: '1',
},
{
type: 'divider',
},
{
label: '3rd menu item(disabled)',
key: '3',
disabled: true,
},
];
const App: React.FC = () => (
<Dropdown menu={{ items }}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
export default App;
중앙을 가리키는 화살표 (Arrow pointing at the center)
arrow prop을 { pointAtCenter: true }로 지정하면 화살표가 타겟 요소의 중앙을 가리켜요.
import React from 'react';
import type { MenuProps } from 'antd';
import { Button, Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
},
{
key: '2',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item
</a>
),
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item
</a>
),
},
];
const App: React.FC = () => (
<Space vertical>
<Space wrap>
<Dropdown menu={{ items }} placement="bottomLeft" arrow={{ pointAtCenter: true }}>
<Button>bottomLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottom" arrow={{ pointAtCenter: true }}>
<Button>bottom</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="bottomRight" arrow={{ pointAtCenter: true }}>
<Button>bottomRight</Button>
</Dropdown>
</Space>
<Space wrap>
<Dropdown menu={{ items }} placement="topLeft" arrow={{ pointAtCenter: true }}>
<Button>topLeft</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="top" arrow={{ pointAtCenter: true }}>
<Button>top</Button>
</Dropdown>
<Dropdown menu={{ items }} placement="topRight" arrow={{ pointAtCenter: true }}>
<Button>topRight</Button>
</Dropdown>
</Space>
</Space>
);
export default App;
트리거 모드 (Trigger mode)
기본 트리거 모드는 hover이고, click으로 변경할 수 있어요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
label: (
<a href="https://www.antgroup.com" target="_blank" rel="noopener noreferrer">
1st menu item
</a>
),
key: '0',
},
{
label: (
<a href="https://www.aliyun.com" target="_blank" rel="noopener noreferrer">
2nd menu item
</a>
),
key: '1',
},
{
type: 'divider',
},
{
label: '3rd menu item',
key: '3',
},
];
const App: React.FC = () => (
<Dropdown menu={{ items }} trigger={['click']}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Click me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
export default App;
클릭 이벤트 (Click event)
메뉴 항목을 클릭하면 이벤트가 트리거되는데, 항목의 key에 따라 서로 다른 작업을 수행할 수 있어요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, message, Space } from 'antd';
const items: MenuProps['items'] = [
{
label: '1st menu item',
key: '1',
},
{
label: '2nd menu item',
key: '2',
},
{
label: '3rd menu item',
key: '3',
},
];
const App: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const onClick: MenuProps['onClick'] = ({ key }) => {
messageApi.info(`Click on item ${key}`);
};
return (
<>
{contextHolder}
<Dropdown menu={{ items, onClick }}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me, Click menu item
<DownOutlined />
</Space>
</a>
</Dropdown>
</>
);
};
export default App;
드롭다운 메뉴가 있는 버튼 (Button with dropdown menu)
왼쪽에 버튼이, 오른쪽에 관련 기능 메뉴가 있어요. icon 속성으로 오른쪽 아이콘을 변경할 수 있어요.
import React from 'react';
import { DownOutlined, EllipsisOutlined, UserOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Button, Dropdown, message, Space, Tooltip } from 'antd';
const items: MenuProps['items'] = [
{
label: '1st menu item',
key: '1',
icon: <UserOutlined />,
},
{
label: '2nd menu item',
key: '2',
icon: <UserOutlined />,
},
{
label: '3rd menu item',
key: '3',
icon: <UserOutlined />,
danger: true,
},
{
label: '4rd menu item',
key: '4',
icon: <UserOutlined />,
danger: true,
disabled: true,
},
];
const App: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const handleButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
messageApi.info('Click on left button.');
console.log('click left button', e);
};
const handleMenuClick: MenuProps['onClick'] = (e) => {
messageApi.info('Click on menu item.');
console.log('click', e);
};
const menuProps = {
items,
onClick: handleMenuClick,
};
return (
<>
{contextHolder}
<Space wrap>
<Space.Compact>
<Button onClick={handleButtonClick}>Dropdown</Button>
<Dropdown menu={menuProps} placement="bottomRight">
<Button icon={<EllipsisOutlined />} />
</Dropdown>
</Space.Compact>
<Space.Compact>
<Button onClick={handleButtonClick}>Dropdown</Button>
<Dropdown menu={menuProps} placement="bottomRight">
<Button icon={<UserOutlined />} />
</Dropdown>
</Space.Compact>
<Space.Compact>
<Button onClick={handleButtonClick} disabled>
Dropdown
</Button>
<Dropdown menu={menuProps} placement="bottomRight" disabled>
<Button icon={<EllipsisOutlined />} disabled />
</Dropdown>
</Space.Compact>
<Space.Compact>
<Tooltip title="tooltip">
<Button onClick={handleButtonClick}>With Tooltip</Button>
</Tooltip>
<Dropdown menu={menuProps} placement="bottomRight">
<Button loading />
</Dropdown>
</Space.Compact>
<Dropdown menu={menuProps}>
<Button onClick={handleButtonClick} icon={<DownOutlined />} iconPlacement="end">
Button
</Button>
</Dropdown>
<Space.Compact>
<Button onClick={handleButtonClick} danger>
Danger
</Button>
<Dropdown menu={menuProps} placement="bottomRight">
<Button icon={<EllipsisOutlined />} danger />
</Dropdown>
</Space.Compact>
</Space>
</>
);
};
export default App;
커스텀 드롭다운 (Custom dropdown)
popupRender를 통해 드롭다운 메뉴를 커스터마이즈할 수 있어요. Menu 콘텐츠가 필요 없다면 Popover 컴포넌트를 직접 사용하세요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import { Button, Divider, Dropdown, Space, theme } from 'antd';
import type { MenuProps } from 'antd';
const { useToken } = theme;
const items: MenuProps['items'] = [
{
key: '1',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
1st menu item
</a>
),
},
{
key: '2',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
2nd menu item (disabled)
</a>
),
disabled: true,
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
3rd menu item (disabled)
</a>
),
disabled: true,
},
];
const App: React.FC = () => {
const { token } = useToken();
const contentStyle: React.CSSProperties = {
backgroundColor: token.colorBgElevated,
borderRadius: token.borderRadiusLG,
boxShadow: token.boxShadowSecondary,
};
const menuStyle: React.CSSProperties = {
boxShadow: 'none',
};
return (
<Dropdown
menu={{ items }}
popupRender={(menu) => (
<div style={contentStyle}>
{React.cloneElement(
menu as React.ReactElement<{
style: React.CSSProperties;
}>,
{ style: menuStyle },
)}
<Divider style={{ margin: 0 }} />
<Space style={{ padding: 8 }}>
<Button type="primary">Click me!</Button>
</Space>
</div>
)}
>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
};
export default App;
캐스케이딩 메뉴 (Cascading menu)
메뉴가 여러 레벨로 구성된 경우예요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
type: 'group',
label: 'Group title',
children: [
{
key: '1-1',
label: '1st menu item',
},
{
key: '1-2',
label: '2nd menu item',
},
],
},
{
key: '2',
label: 'sub menu',
children: [
{
key: '2-1',
label: '3rd menu item',
},
{
key: '2-2',
label: '4th menu item',
},
],
},
{
key: '3',
label: 'disabled sub menu',
disabled: true,
children: [
{
key: '3-1',
label: '5d menu item',
},
{
key: '3-2',
label: '6th menu item',
},
],
},
];
const App: React.FC = () => (
<Dropdown menu={{ items }}>
<a onClick={(e) => e.preventDefault()}>
<Space>
Cascading menu
<DownOutlined />
</Space>
</a>
</Dropdown>
);
export default App;
메뉴 숨김 방식 (The way of hiding menu)
기본적으로 메뉴 항목을 클릭하면 메뉴가 닫혀요. 이 기능을 끌 수 있어요.
import React, { useState } from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { DropdownProps, MenuProps } from 'antd';
import { Dropdown, Space } from 'antd';
const App: React.FC = () => {
const [open, setOpen] = useState(false);
const handleMenuClick: MenuProps['onClick'] = (e) => {
if (e.key === '3') {
setOpen(false);
}
};
const handleOpenChange: DropdownProps['onOpenChange'] = (nextOpen, info) => {
if (info.source === 'trigger' || nextOpen) {
setOpen(nextOpen);
}
};
const items: MenuProps['items'] = [
{
label: 'Clicking me will not close the menu.',
key: '1',
},
{
label: 'Clicking me will not close the menu also.',
key: '2',
},
{
label: 'Clicking me will close the menu.',
key: '3',
},
];
return (
<Dropdown
menu={{
items,
onClick: handleMenuClick,
}}
onOpenChange={handleOpenChange}
open={open}
>
<a onClick={(e) => e.preventDefault()}>
<Space>
Hover me
<DownOutlined />
</Space>
</a>
</Dropdown>
);
};
export default App;
컨텍스트 메뉴 (Context Menu)
기본 트리거 모드는 hover이고, contextMenu로 변경할 수 있어요. 팝업 메뉴 위치는 오른쪽 클릭 위치를 따라가요.
import React from 'react';
import type { MenuProps } from 'antd';
import { Dropdown, theme } from 'antd';
const items: MenuProps['items'] = [
{
label: '1st menu item',
key: '1',
},
{
label: '2nd menu item',
key: '2',
},
{
label: '3rd menu item',
key: '3',
},
];
const App: React.FC = () => {
const {
token: { colorBgLayout, colorTextTertiary },
} = theme.useToken();
return (
<Dropdown menu={{ items }} trigger={['contextMenu']}>
<div
style={{
color: colorTextTertiary,
background: colorBgLayout,
height: 200,
textAlign: 'center',
lineHeight: '200px',
}}
>
Right Click on here
</div>
</Dropdown>
);
};
export default App;
로딩 (Loading)
loading 속성을 설정해 버튼에 로딩 표시를 추가할 수 있어요.
import React, { useState } from 'react';
import { DownOutlined, EllipsisOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Button, Dropdown, Space } from 'antd';
const items: MenuProps['items'] = [
{
label: 'Submit and continue',
key: '1',
},
];
const App: React.FC = () => {
const [loadings, setLoadings] = useState<boolean[]>([]);
const enterLoading = (index: number) => {
setLoadings((state) => {
const newLoadings = [...state];
newLoadings[index] = true;
return newLoadings;
});
setTimeout(() => {
setLoadings((state) => {
const newLoadings = [...state];
newLoadings[index] = false;
return newLoadings;
});
}, 6000);
};
return (
<Space vertical>
<Space.Compact>
<Button type="primary" loading>
Submit
</Button>
<Dropdown menu={{ items }}>
<Button type="primary" icon={<EllipsisOutlined />} />
</Dropdown>
</Space.Compact>
<Space.Compact size="small">
<Button type="primary" loading>
Submit
</Button>
<Dropdown menu={{ items }}>
<Button type="primary" icon={<EllipsisOutlined />} />
</Dropdown>
</Space.Compact>
<Space.Compact>
<Button type="primary" loading={loadings[0]} onClick={() => enterLoading(0)}>
Submit
</Button>
<Dropdown menu={{ items }}>
<Button type="primary" icon={<EllipsisOutlined />} />
</Dropdown>
</Space.Compact>
<Space.Compact>
<Button loading={loadings[1]} onClick={() => enterLoading(1)}>
Submit
</Button>
<Dropdown menu={{ items }}>
<Button icon={<DownOutlined />} />
</Dropdown>
</Space.Compact>
</Space>
);
};
export default App;
선택 가능한 메뉴 (Selectable Menu)
menu에서 selectable 속성을 설정해 선택 기능을 활성화할 수 있어요.
import React from 'react';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Dropdown, Space, Typography } from 'antd';
const items: MenuProps['items'] = [
{
key: '1',
label: 'Item 1',
},
{
key: '2',
label: 'Item 2',
},
{
key: '3',
label: 'Item 3',
},
];
const App: React.FC = () => (
<Dropdown
menu={{
items,
selectable: true,
defaultSelectedKeys: ['3'],
}}
>
<Typography.Link>
<Space>
Selectable
<DownOutlined />
</Space>
</Typography.Link>
</Dropdown>
);
export default App;
선택 동작 (Selection actions)
브라우저의 Selection API와 함께 Dropdown을 사용해 텍스트를 선택한 뒤 커스텀 동작을 보여 줄 수 있어요.
import React, { useRef, useState } from 'react';
import type { MenuProps } from 'antd';
import { Dropdown, message } from 'antd';
import { createStyles } from 'antd-style';
import type { ItemType } from 'antd/es/menu/interface';
interface SelectionInfo {
text: string;
x: number;
y: number;
}
const labels: Record<string, string> = {
mask: 'Mask keyword',
mark: 'Mark keyword',
search: 'Search keyword',
};
const useStyle = createStyles(({ cssVar, css }) => {
const { colorText, colorBgLayout, borderRadiusLG, paddingLG } = cssVar;
return {
wrapper: css`
padding: ${paddingLG};
user-select: text;
color: ${colorText};
background-color: ${colorBgLayout};
border-radius: ${borderRadiusLG};
`,
trigger: css`
position: fixed;
display: block;
width: 1px;
height: 1px;
margin: 0;
padding: 0;
pointer-events: none;
`,
};
});
const items = Object.entries(labels).map<ItemType>(([key, label]) => ({ key, label }));
const Demo: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const { styles } = useStyle();
const wrapperRef = useRef<HTMLDivElement>(null);
const [selection, setSelection] = useState<SelectionInfo | null>(null);
const handleSelect = () => {
const selectionInstance = window.getSelection();
const selectedText = selectionInstance?.toString().trim();
if (!selectionInstance || !selectedText || selectionInstance.rangeCount === 0) {
setSelection(null);
return;
}
const range = selectionInstance.getRangeAt(0);
if (!wrapperRef.current?.contains(range.commonAncestorContainer)) {
setSelection(null);
return;
}
const rect = range.getBoundingClientRect();
if (!rect.width || !rect.height) {
setSelection(null);
return;
}
setSelection({
text: selectedText,
x: rect.left + rect.width / 2,
y: rect.bottom + 4,
});
};
const handleMouseUp: React.MouseEventHandler<HTMLDivElement> = () => {
setTimeout(handleSelect);
};
const handleMenuClick: MenuProps['onClick'] = ({ key }) => {
if (!selection) {
return;
}
messageApi.info(`${labels[key]}: ${selection.text}`);
window.getSelection()?.removeAllRanges();
setSelection(null);
};
return (
<>
{contextHolder}
<Dropdown
menu={{ items, onClick: handleMenuClick }}
open={Boolean(selection)}
placement="bottom"
trigger={[]}
onOpenChange={(nextOpen) => {
if (!nextOpen) {
setSelection(null);
}
}}
>
<span
aria-hidden
className={styles.trigger}
style={{
left: selection?.x ?? -9999,
top: selection?.y ?? -9999,
}}
/>
</Dropdown>
<div
ref={wrapperRef}
onMouseDown={() => setSelection(null)}
onMouseUp={handleMouseUp}
className={styles.wrapper}
>
Select any text in this paragraph to open a Dropdown menu near the selection. This is useful
for actions such as masking sensitive words, marking entities, or searching the selected
keyword. Example data: Alice, phone 13800138000, ID 110101199001011234.
</div>
</>
);
};
export default Demo;
커스텀 시맨틱 DOM 스타일 (Custom semantic dom styling)
classNames와 styles로 객체/함수를 넘겨 Dropdown의 시맨틱 DOM 스타일을 커스터마이즈할 수 있어요.
import React from 'react';
import { DownOutlined, LogoutOutlined, SettingOutlined } from '@ant-design/icons';
import { Button, Dropdown, Flex, Space } from 'antd';
import type { DropdownProps, GetProp, MenuProps } from 'antd';
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => ({
root: {
backgroundColor: token.colorFillAlter,
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
borderRadius: token.borderRadius,
},
}));
const items: MenuProps['items'] = [
{
key: '1',
label: 'Profile',
},
{
key: '2',
label: 'Settings',
icon: <SettingOutlined />,
},
{
type: 'divider',
},
{
key: '3',
label: 'Logout',
icon: <LogoutOutlined />,
danger: true,
},
];
const objectStyles: DropdownProps['styles'] = {
root: {
backgroundColor: '#fff',
border: '1px solid #d9d9d9',
borderRadius: '4px',
},
item: {
padding: '8px 12px',
fontSize: '14px',
},
itemTitle: {
fontWeight: '500',
},
itemIcon: {
color: '#1890ff',
marginInlineEnd: '8px',
},
itemContent: {
backgroundColor: 'transparent',
},
};
const functionStyles: DropdownProps['styles'] = (
info,
): GetProp<DropdownProps, 'styles', 'Return'> => {
const { props } = info;
const isClick = props.trigger?.includes('click');
if (isClick) {
return {
root: {
borderColor: '#1890ff',
borderRadius: '8px',
},
};
}
return {};
};
const App: React.FC = () => {
const { styles } = useStyles();
const sharedProps: DropdownProps = {
menu: { items },
placement: 'bottomLeft',
classNames: { root: styles.root },
};
return (
<Flex gap="medium" wrap="wrap">
<Space vertical size="large">
<Dropdown {...sharedProps} styles={objectStyles}>
<Button>
<Space>
Object Style
<DownOutlined />
</Space>
</Button>
</Dropdown>
<Dropdown {...sharedProps} styles={functionStyles} trigger={['click']}>
<Button type="primary">
<Space>
Function Style
<DownOutlined />
</Space>
</Button>
</Dropdown>
</Space>
</Flex>
);
};
export default App;
API
공통 props 참조: Common props
Dropdown
| 속성 | 설명 | 타입 | 기본값 | 버전 | 전역 설정 |
|---|---|---|---|---|---|
| arrow | 드롭다운 화살표 표시 여부 | boolean | { pointAtCenter: boolean } | false | × | |
| autoAdjustOverflow | 드롭다운이 화면 밖일 때 위치를 자동으로 조정할지 여부 | boolean | true | 5.2.0 | × |
| classNames | Dropdown 컴포넌트 내 각 시맨틱 구조에 대한 클래스를 커스터마이즈. 객체 또는 함수를 지원 | Record<SemanticDOM, string> | (info: { props }) => Record<SemanticDOM, string> | - | 6.0.0 | |
| disabled | 드롭다운 메뉴 비활성화 여부 | boolean | - | × | |
숨길 때 드롭다운을 파괴할지 여부, destroyOnHidden을 대신 사용 |
boolean | false | × | ||
| destroyOnHidden | 숨길 때 드롭다운을 파괴할지 여부 | boolean | false | 5.25.0 | × |
드롭다운 콘텐츠 커스터마이즈, popupRender를 대신 사용 |
(menus: ReactNode) => ReactNode | - | 4.24.0 | × | |
| popupRender | 팝업 콘텐츠 커스터마이즈 | (menus: ReactNode) => ReactNode | - | 5.25.0 | × |
| getPopupContainer | 드롭다운 메뉴의 컨테이너 설정. 기본은 body에 div를 만들지만, 스크롤 영역으로 재설정하고 상대 재배치할 수 있음. CodePen 예시 | (triggerNode: HTMLElement) => HTMLElement | () => document.body | × | |
| menu | 메뉴 props | MenuProps | - | × | |
드롭다운 루트 요소의 클래스 이름, classNames.root를 대신 사용 |
string | - | × | ||
드롭다운 루트 요소의 스타일, styles.root를 대신 사용 |
CSSProperties | - | × | ||
| placement | 팝업 메뉴 위치: top topLeft topRight bottom bottomLeft bottomRight left leftTop leftBottom right rightTop rightBottom |
string | bottomLeft |
left leftTop leftBottom right rightTop rightBottom: 6.5.0 |
× |
| styles | Dropdown 컴포넌트 내 각 시맨틱 구조에 대한 인라인 스타일을 커스터마이즈. 객체 또는 함수를 지원 | Record<SemanticDOM, CSSProperties> | (info: { props }) => Record<SemanticDOM, CSSProperties> | - | 6.0.0 | |
| trigger | 드롭다운 동작을 실행하는 트리거 모드. 참고로 호버는 터치스크린에서 사용할 수 없음 | Array<click|hover|contextMenu> |
[hover] |
× | |
| open | 드롭다운 메뉴가 현재 열려 있는지 여부 | boolean | - | × | |
| onOpenChange | 열림 상태가 변경될 때 호출됨. 항목 클릭으로 숨길 때는 트리거되지 않음 | (open: boolean, info: { source: 'trigger' | 'menu' }) => void | - | info.source: 5.11.0 |
× |
참고 (Note)
Dropdown의 하위 노드가 onMouseEnter, onMouseLeave, onFocus, onClick 이벤트를 받을 수 있도록 해 주세요.
Semantic DOM
https://ant.design/components/dropdown/semantic.md
Design Token
Component Token (Dropdown)
| 토큰 이름 | 설명 | 타입 | 기본값 |
|---|---|---|---|
| paddingBlock | dropdown의 세로 패딩 | PaddingBlock<string | number> | undefined | 5 |
| zIndexPopup | dropdown의 z-index | number | 1050 |
Global Token
| 토큰 이름 | 설명 | 타입 | 기본값 |
|---|---|---|---|
| borderRadiusLG | LG 크기의 테두리 반경. Card, Modal 등 큰 테두리 반경 컴포넌트에서 사용 | number | |
| borderRadiusSM | SM 크기의 테두리 반경. 작은 크기 입력 컴포넌트(Button, Input, Select 등)에서 사용 | number | |
| borderRadiusXS | XS 크기의 테두리 반경. Segmented, Arrow 등 작은 테두리 반경 컴포넌트에서 사용 | number | |
| boxShadowSecondary | 요소의 2차 박스 섀도 스타일 제어 | string | |
| colorBgElevated | 팝업 레이어의 컨테이너 배경색. 다크 모드에서는 colorBgContainer보다 밝음. 예: modal, pop-up, menu 등 |
string | |
| colorError | 작업 실패를 나타내는 시각 요소. 예: error Button, error Result 컴포넌트 등 | string | |
| colorIcon | 약한 동작. allowClear나 Alert 닫기 버튼 등 |
string | |
| colorPrimary | 브랜드 색상은 제품의 특성과 커뮤니케이션을 반영하는 가장 직접적인 시각 요소 중 하나 | string | |
| colorPrimaryBorder | 메인 색 그라데이션의 획 색상. Slider 등 컴포넌트의 획에 사용 | string | |
| colorSplit | 구분선의 색상으로 사용. colorBorderSecondary와 같지만 투명도를 가짐 | string | |
| colorText | W3C 표준을 따르는 기본 텍스트 색상. 가장 어두운 중립 색 | string | |
| colorTextDescription | 텍스트 설명의 글꼴 색상 제어 | string | |
| colorTextDisabled | 비활성 상태 텍스트의 색상 제어 | string | |
| colorTextLightSolid | 배경색이 있는 텍스트의 하이라이트 색상 제어. 예: Primary Button 컴포넌트의 텍스트 | string | |
| controlHeightLG | LG 컴포넌트 높이 | number | |
| controlItemBgActive | 활성 상태일 때 제어 컴포넌트 항목의 배경색 제어 | string | |
| controlItemBgActiveHover | 호버하면서 활성 상태일 때 제어 컴포넌트 항목의 배경색 제어 | string | |
| controlItemBgHover | 호버 시 제어 컴포넌트 항목의 배경색 제어 | string | |
| controlPaddingHorizontal | 요소의 가로 패딩 제어 | number | |
| fontFamily | Ant Design의 글꼴 패밀리는 시스템 기본 인터페이스 글꼴을 우선하며, 화면 표시에 적합한 대체 글꼴 라이브러리를 제공 | string | |
| fontSize | 디자인 시스템에서 가장 널리 쓰이는 글꼴 크기. 텍스트 그라데이션이 여기서 파생됨 | number | |
| fontSizeIcon | Select, Cascader 등의 동작 아이콘 글꼴 크기 제어. 보통 fontSizeSM과 같음 | number | |
| fontSizeSM | 작은 글꼴 크기 | number | |
| lineHeight | 텍스트의 줄 높이 | number | |
| lineWidthFocus | 컴포넌트가 포커스 상태일 때 라인의 너비 제어 | number | |
| marginXS | 요소의 여백을 작은 크기로 제어 | number | |
| marginXXS | 요소의 여백을 가장 작은 크기로 제어 | number | |
| motionDurationMid | 중간 속도 모션. 중간 요소 애니메이션 상호작용에 사용 | string | |
| motionEaseInOutCirc | 사전 설정된 모션 커브 | string | |
| motionEaseInQuint | 사전 설정된 모션 커브 | string | |
| motionEaseOutCirc | 사전 설정된 모션 커브 | string | |
| motionEaseOutQuint | 사전 설정된 모션 커브 | string | |
| padding | 요소의 패딩 제어 | number | |
| paddingXS | 요소의 매우 작은 패딩 제어 | number | |
| paddingXXS | 요소의 아주 아주 작은 패딩 제어 | number | |
| sizePopupArrow | 컴포넌트 화살표의 크기 | number |
FAQ
Dropdown이 화면을 가로로 초과할 때 찌그러지지 않게 하려면 어떻게 하나요? {#faq-dropdown-squeezed}
width: max-content 스타일을 사용해 처리할 수 있어요. #43025 참고.