Skip to main content
Glama

antd-components-mcp

examples.md47.8 kB
## Modal 组件示例 ### 基本 基础弹框。 ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const showModal = () => { setIsModalOpen(true); }; const handleOk = () => { setIsModalOpen(false); }; const handleCancel = () => { setIsModalOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal </Button> <Modal title="Basic Modal" closable={{ 'aria-label': 'Custom Close Button' }} open={isModalOpen} onOk={handleOk} onCancel={handleCancel} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 异步关闭 点击确定后异步关闭对话框,例如提交表单。 ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [open, setOpen] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [modalText, setModalText] = useState('Content of the modal'); const showModal = () => { setOpen(true); }; const handleOk = () => { setModalText('The modal will be closed after two seconds'); setConfirmLoading(true); setTimeout(() => { setOpen(false); setConfirmLoading(false); }, 2000); }; const handleCancel = () => { console.log('Clicked cancel button'); setOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal with async logic </Button> <Modal title="Title" open={open} onOk={handleOk} confirmLoading={confirmLoading} onCancel={handleCancel} > <p>{modalText}</p> </Modal> </> ); }; export default App; ``` ### 自定义页脚 更复杂的例子,自定义了页脚的按钮,点击提交后进入 loading 状态,完成后关闭。 不需要默认确定取消按钮时,你可以把 `footer` 设为 `null`。 ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); const showModal = () => { setOpen(true); }; const handleOk = () => { setLoading(true); setTimeout(() => { setLoading(false); setOpen(false); }, 3000); }; const handleCancel = () => { setOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal with customized footer </Button> <Modal open={open} title="Title" onOk={handleOk} onCancel={handleCancel} footer={[ <Button key="back" onClick={handleCancel}> Return </Button>, <Button key="submit" type="primary" loading={loading} onClick={handleOk}> Submit </Button>, <Button key="link" href="https://google.com" target="_blank" type="primary" loading={loading} onClick={handleOk} > Search on Google </Button>, ]} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 加载中 设置对话框加载状态。 ```tsx import React from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [open, setOpen] = React.useState<boolean>(false); const [loading, setLoading] = React.useState<boolean>(true); const showLoading = () => { setOpen(true); setLoading(true); // Simple loading mock. You should add cleanup logic in real world. setTimeout(() => { setLoading(false); }, 2000); }; return ( <> <Button type="primary" onClick={showLoading}> Open Modal </Button> <Modal title={<p>Loading Modal</p>} footer={ <Button type="primary" onClick={showLoading}> Reload </Button> } loading={loading} open={open} onCancel={() => setOpen(false)} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 自定义页脚渲染函数 自定义页脚渲染函数,支持在原有基础上进行扩展。 ```tsx import React, { useState } from 'react'; import { Button, Modal, Space } from 'antd'; const App: React.FC = () => { const [open, setOpen] = useState(false); const showModal = () => { setOpen(true); }; const handleOk = () => { setOpen(false); }; const handleCancel = () => { setOpen(false); }; return ( <> <Space> <Button type="primary" onClick={showModal}> Open Modal </Button> <Button type="primary" onClick={() => { Modal.confirm({ title: 'Confirm', content: 'Bla bla ...', footer: (_, { OkBtn, CancelBtn }) => ( <> <Button>Custom Button</Button> <CancelBtn /> <OkBtn /> </> ), }); }} > Open Modal Confirm </Button> </Space> <Modal open={open} title="Title" onOk={handleOk} onCancel={handleCancel} footer={(_, { OkBtn, CancelBtn }) => ( <> <Button>Custom Button</Button> <CancelBtn /> <OkBtn /> </> )} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 使用 hooks 获得上下文 通过 `Modal.useModal` 创建支持读取 context 的 `contextHolder`。其中仅有 hooks 方法支持 Promise `await` 操作。 ```tsx import React, { createContext } from 'react'; import { Button, Modal, Space } from 'antd'; const ReachableContext = createContext<string | null>(null); const UnreachableContext = createContext<string | null>(null); const config = { title: 'Use Hook!', content: ( <> <ReachableContext.Consumer>{(name) => `Reachable: ${name}!`}</ReachableContext.Consumer> <br /> <UnreachableContext.Consumer>{(name) => `Unreachable: ${name}!`}</UnreachableContext.Consumer> </> ), }; const App: React.FC = () => { const [modal, contextHolder] = Modal.useModal(); return ( <ReachableContext.Provider value="Light"> <Space> <Button onClick={async () => { const confirmed = await modal.confirm(config); console.log('Confirmed: ', confirmed); }} > Confirm </Button> <Button onClick={() => { modal.warning(config); }} > Warning </Button> <Button onClick={async () => { modal.info(config); }} > Info </Button> <Button onClick={async () => { modal.error(config); }} > Error </Button> </Space> {/* `contextHolder` should always be placed under the context you want to access */} {contextHolder} {/* Can not access this context since `contextHolder` is not in it */} <UnreachableContext.Provider value="Bamboo" /> </ReachableContext.Provider> ); }; export default App; ``` ### 国际化 设置 `okText` 与 `cancelText` 以自定义按钮文字。 ```tsx import React, { useState } from 'react'; import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Button, Modal, Space } from 'antd'; const LocalizedModal = () => { const [open, setOpen] = useState(false); const showModal = () => { setOpen(true); }; const hideModal = () => { setOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Modal </Button> <Modal title="Modal" open={open} onOk={hideModal} onCancel={hideModal} okText="确认" cancelText="取消" > <p>Bla bla ...</p> <p>Bla bla ...</p> <p>Bla bla ...</p> </Modal> </> ); }; const App: React.FC = () => { const [modal, contextHolder] = Modal.useModal(); const confirm = () => { modal.confirm({ title: 'Confirm', icon: <ExclamationCircleOutlined />, content: 'Bla bla ...', okText: '确认', cancelText: '取消', }); }; return ( <> <Space> <LocalizedModal /> <Button onClick={confirm}>Confirm</Button> </Space> {contextHolder} </> ); }; export default App; ``` ### 手动更新和移除 通过返回的 instance 手动更新和关闭对话框。 ```tsx import React from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [modal, contextHolder] = Modal.useModal(); const countDown = () => { let secondsToGo = 5; const instance = modal.success({ title: 'This is a notification message', content: `This modal will be destroyed after ${secondsToGo} second.`, }); const timer = setInterval(() => { secondsToGo -= 1; instance.update({ content: `This modal will be destroyed after ${secondsToGo} second.`, }); }, 1000); setTimeout(() => { clearInterval(timer); instance.destroy(); }, secondsToGo * 1000); }; return ( <> <Button onClick={countDown}>Open modal to close in 5s</Button> {contextHolder} </> ); }; export default App; ``` ### 自定义位置 使用 `centered` 或类似 `style.top` 的样式来设置对话框位置。 ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [modal1Open, setModal1Open] = useState(false); const [modal2Open, setModal2Open] = useState(false); return ( <> <Button type="primary" onClick={() => setModal1Open(true)}> Display a modal dialog at 20px to Top </Button> <Modal title="20px to Top" style={{ top: 20 }} open={modal1Open} onOk={() => setModal1Open(false)} onCancel={() => setModal1Open(false)} > <p>some contents...</p> <p>some contents...</p> <p>some contents...</p> </Modal> <br /> <br /> <Button type="primary" onClick={() => setModal2Open(true)}> Vertically centered modal dialog </Button> <Modal title="Vertically centered modal dialog" centered open={modal2Open} onOk={() => setModal2Open(false)} onCancel={() => setModal2Open(false)} > <p>some contents...</p> <p>some contents...</p> <p>some contents...</p> </Modal> </> ); }; export default App; ``` ### 暗背景 第一个对话框。 ```tsx import React, { useState } from 'react'; import { ClockCircleOutlined, DownOutlined } from '@ant-design/icons'; import { Anchor, Badge, Button, Calendar, Card, Collapse, DatePicker, Dropdown, Modal, Slider, Switch, Table, Tabs, Timeline, Transfer, Tree, Typography, } from 'antd'; import type { TableProps, TransferProps } from 'antd'; import type { TransferKey } from 'antd/es/transfer/interface'; import dayjs from 'dayjs'; import customParseFormat from 'dayjs/plugin/customParseFormat'; import difference from 'lodash/difference'; dayjs.extend(customParseFormat); const { Panel } = Collapse; const { TreeNode } = Tree; const { TabPane } = Tabs; const { Meta } = Card; const { Link } = Anchor; const { Text } = Typography; const text = ` A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome guest in many households across the world. `; interface DataType { key: string; title: string; description: string; disabled: boolean; } interface RecordType { key: string; name: string; age: number; address: string; } interface DataTableType { key: string; name: string; borrow: number; repayment: number; } interface ExpandDataType { key: React.Key; date: string; name: string; upgradeNum: string; } interface NestDataType { key: React.Key; name: string; platform: string; version: string; upgradeNum: number; creator: string; createdAt: string; } interface FixedDataType { key: string; name: string; age: number; address: string; } const mockData = Array.from({ length: 20 }).map<DataType>((_, i) => ({ key: i.toString(), title: `content${i + 1}`, description: `description of content${i + 1}`, disabled: i % 3 < 1, })); const oriTargetKeys = mockData .filter((item) => Number(item.key) % 3 > 1) .map<TransferKey>((item) => item.key); const dataSource: RecordType[] = [ { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park' }, { key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' }, { key: '3', name: 'Joe Black', age: 32, address: 'Sydney No. 1 Lake Park' }, { key: '4', name: 'Jim Red', age: 32, address: 'London No. 2 Lake Park' }, ]; const columnsTable: TableProps<DataTableType>['columns'] = [ { title: 'Name', dataIndex: 'name' }, { title: 'Borrow', dataIndex: 'borrow' }, { title: 'Repayment', dataIndex: 'repayment' }, ]; const summaryDataSource: DataTableType[] = [ { key: '1', name: 'John Brown', borrow: 10, repayment: 33 }, { key: '2', name: 'Jim Green', borrow: 100, repayment: 0 }, { key: '3', name: 'Joe Black', borrow: 10, repayment: 10 }, { key: '4', name: 'Jim Red', borrow: 75, repayment: 45 }, ]; const expandDataSource = Array.from({ length: 3 }).map<ExpandDataType>((_, i) => ({ key: i, date: '2014-12-24 23:12:00', name: 'This is production name', upgradeNum: 'Upgraded: 56', })); const expandColumns: TableProps<ExpandDataType>['columns'] = [ { title: 'Date', dataIndex: 'date', key: 'date' }, { title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'Status', key: 'state', render: () => ( <span> <Badge status="success" /> Finished </span> ), }, { title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' }, { title: 'Action', dataIndex: 'operation', key: 'operation', render: () => ( <span className="table-operation"> <a>Pause</a> <a>Stop</a> <Dropdown> <a> More <DownOutlined /> </a> </Dropdown> </span> ), }, ]; const expandedRowRender = () => ( <Table<ExpandDataType> columns={expandColumns} dataSource={expandDataSource} pagination={false} /> ); const columnsNest: TableProps<NestDataType>['columns'] = [ { title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'Platform', dataIndex: 'platform', key: 'platform' }, { title: 'Version', dataIndex: 'version', key: 'version' }, { title: 'Upgraded', dataIndex: 'upgradeNum', key: 'upgradeNum' }, { title: 'Creator', dataIndex: 'creator', key: 'creator' }, { title: 'Date', dataIndex: 'createdAt', key: 'createdAt' }, { title: 'Action', key: 'operation', render: () => <a>Publish</a> }, ]; const nestDataSource = Array.from({ length: 3 }).map<NestDataType>((_, i) => ({ key: i, name: 'Screem', platform: 'iOS', version: '10.3.4.5654', upgradeNum: 500, creator: 'Jack', createdAt: '2014-12-24 23:12:00', })); const columnsFixed: TableProps<FixedDataType>['columns'] = [ { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' }, { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' }, { title: 'Column 1', dataIndex: 'address', key: '1' }, { title: 'Column 2', dataIndex: 'address', key: '2' }, { title: 'Column 3', dataIndex: 'address', key: '3' }, { title: 'Column 4', dataIndex: 'address', key: '4' }, { title: 'Column 5', dataIndex: 'address', key: '5' }, { title: 'Column 6', dataIndex: 'address', key: '6' }, { title: 'Column 7', dataIndex: 'address', key: '7' }, { title: 'Column 8', dataIndex: 'address', key: '8' }, { title: 'Action', key: 'operation', fixed: 'right', width: 100, render: () => <a>action</a> }, ]; const fixedDataSource: FixedDataType[] = [ { key: '1', name: 'John Brown', age: 32, address: 'New York Park' }, { key: '2', name: 'Jim Green', age: 40, address: 'London Park' }, ]; const TableTransfer: React.FC< Readonly<Partial<Record<'leftColumns' | 'rightColumns', TableProps<DataType>['columns']>>> & TransferProps<DataType> > = (props) => { const { leftColumns, rightColumns, ...restProps } = props; return ( <Transfer<DataType> {...restProps} showSelectAll={false}> {(transferProps) => { const { direction, filteredItems, onItemSelectAll, onItemSelect, selectedKeys: listSelectedKeys, disabled: listDisabled, } = transferProps; const columns = (direction === 'left' ? leftColumns : rightColumns) ?? []; const rowSelection: TableProps<DataType>['rowSelection'] = { getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }), onSelectAll(selected, selectedRows) { const treeSelectedKeys = selectedRows .filter((item) => !item.disabled) .map(({ key }) => key); const diffKeys = selected ? difference(treeSelectedKeys, listSelectedKeys) : difference(listSelectedKeys, treeSelectedKeys); onItemSelectAll(diffKeys, selected); }, onSelect({ key }, selected) { onItemSelect(key, selected); }, selectedRowKeys: listSelectedKeys, }; return ( <Table<DataType> id="components-transfer-table" rowSelection={rowSelection} columns={columns} dataSource={filteredItems} size="small" style={{ pointerEvents: listDisabled ? 'none' : 'auto' }} onRow={({ key, disabled: itemDisabled }) => ({ onClick: () => { if (itemDisabled || listDisabled) { return; } onItemSelect(key, !listSelectedKeys.includes(key)); }, })} /> ); }} </Transfer> ); }; const columns: TableProps<RecordType>['columns'] = [ { title: 'Name', dataIndex: 'name', key: 'name', filters: [ { text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }, ], filteredValue: null, onFilter: (value, record) => record.name.includes(value as string), sorter: (a, b) => a.name.length - b.name.length, sortOrder: 'ascend', ellipsis: true, }, { title: 'Age', dataIndex: 'age', key: 'age', sorter: false, sortOrder: 'ascend', ellipsis: true, }, { title: 'Address', dataIndex: 'address', key: 'address', filters: [ { text: 'London', value: 'London' }, { text: 'New York', value: 'New York' }, ], filteredValue: null, onFilter: (value, record) => record.address.includes(value as string), sorter: false, sortOrder: 'ascend', ellipsis: true, }, ]; const tableTransferColumns: TableProps<DataType>['columns'] = [ { dataIndex: 'title', title: 'Name' }, { dataIndex: 'description', title: 'Description' }, ]; const Demo: React.FC = () => { const [open, setOpen] = useState(false); const [targetKeys, setTargetKeys] = useState<TransferKey[]>(oriTargetKeys); const [selectedKeys, setSelectedKeys] = useState<TransferKey[]>([]); const [disabled, setDisabled] = useState(false); const [showSearch, setShowSearch] = useState(false); const handleDisable = (isDisabled: boolean) => { setDisabled(isDisabled); }; const handleTableTransferChange = (nextTargetKeys: TransferKey[]) => { setTargetKeys(nextTargetKeys); }; const triggerDisable = (isDisabled: boolean) => { setDisabled(isDisabled); }; const triggerShowSearch = (isShowSearch: boolean) => { setShowSearch(isShowSearch); }; const handleTransferChange = (keys: TransferKey[]) => { setTargetKeys(keys); }; const handleTransferSelectChange = ( sourceSelectedKeys: TransferKey[], targetSelectedKeys: TransferKey[], ) => { setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]); }; const showModal = () => { setOpen(true); }; const handleOk = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { console.log(e); setOpen(false); }; const handleCancel = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { console.log(e); setOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal </Button> <Modal title="Basic Modal" open={open} onOk={handleOk} onCancel={handleCancel}> <Switch unCheckedChildren="disabled" checkedChildren="disabled" checked={disabled} onChange={handleDisable} style={{ marginBottom: 16 }} /> <Card title="Card Title"> <Card.Grid>Content</Card.Grid> <Card.Grid hoverable={false}>Content</Card.Grid> <Card.Grid>Content</Card.Grid> <Card.Grid>Content</Card.Grid> <Card.Grid>Content</Card.Grid> <Card.Grid>Content</Card.Grid> <Card.Grid>Content</Card.Grid> </Card> <Collapse> <Panel header="This is panel header 1" key="1"> <Collapse defaultActiveKey="1"> <Panel header="This is panel nest panel" key="1"> <p>{text}</p> </Panel> </Collapse> </Panel> <Panel header="This is panel header 2" key="2"> <p>{text}</p> </Panel> <Panel header="This is panel header 3" key="3"> <p>{text}</p> </Panel> </Collapse> <Transfer<DataType> dataSource={mockData} titles={['Source', 'Target']} targetKeys={targetKeys} selectedKeys={selectedKeys} onChange={handleTransferChange} onSelectChange={handleTransferSelectChange} render={(item) => item.title} disabled={disabled} /> <TableTransfer dataSource={mockData} targetKeys={targetKeys} disabled={disabled} showSearch={showSearch} leftColumns={tableTransferColumns} rightColumns={tableTransferColumns} onChange={handleTableTransferChange} filterOption={(inputValue: string, item: any) => item.title?.includes(inputValue) || item.tag?.includes(inputValue) } /> <Switch unCheckedChildren="disabled" checkedChildren="disabled" checked={disabled} onChange={triggerDisable} style={{ marginTop: 16 }} /> <Switch unCheckedChildren="showSearch" checkedChildren="showSearch" checked={showSearch} onChange={triggerShowSearch} style={{ marginTop: 16 }} /> <Anchor> <Link href="#anchor-demo-basic" title="Basic demo" /> <Link href="#anchor-demo-static" title="Static demo" /> <Link href="#anchor-demo-basic" title="Basic demo with Target" target="_blank" /> <Link href="#API" title="API"> <Link href="#Anchor-Props" title="Anchor Props" /> <Link href="#Link-Props" title="Link Props" /> </Link> </Anchor> <Tabs type="card"> <TabPane tab="Tab 1" key="1"> Content of Tab Pane 1 </TabPane> <TabPane tab="Tab 2" key="2"> Content of Tab Pane 2 </TabPane> <TabPane tab="Tab 3" key="3"> Content of Tab Pane 3 </TabPane> </Tabs> <Timeline> <Timeline.Item>Create a services site 2015-09-01</Timeline.Item> <Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item> <Timeline.Item dot={<ClockCircleOutlined style={{ fontSize: '16px' }} />} color="red"> Technical testing 2015-09-01 </Timeline.Item> <Timeline.Item>Network problems being solved 2015-09-01</Timeline.Item> </Timeline> <Calendar /> <Tree showLine switcherIcon={<DownOutlined />} defaultExpandedKeys={['0-0-0']}> <TreeNode title="parent 1" key="0-0"> <TreeNode title="parent 1-0" key="0-0-0"> <TreeNode title="leaf" key="0-0-0-0" /> <TreeNode title="leaf" key="0-0-0-1" /> <TreeNode title="leaf" key="0-0-0-2" /> </TreeNode> <TreeNode title="parent 1-1" key="0-0-1"> <TreeNode title="leaf" key="0-0-1-0" /> </TreeNode> <TreeNode title="parent 1-2" key="0-0-2"> <TreeNode title="leaf" key="0-0-2-0" /> <TreeNode title="leaf" key="0-0-2-1" /> </TreeNode> </TreeNode> </Tree> <Table<RecordType> columns={columns} dataSource={dataSource} footer={() => 'Footer'} /> <Table<DataTableType> columns={columnsTable} dataSource={summaryDataSource} pagination={false} id="table-demo-summary" bordered summary={(pageData) => { let totalBorrow = 0; let totalRepayment = 0; pageData.forEach(({ borrow, repayment }) => { totalBorrow += borrow; totalRepayment += repayment; }); return ( <> <tr> <th>Total</th> <td> <Text type="danger">{totalBorrow}</Text> </td> <td> <Text>{totalRepayment}</Text> </td> </tr> <tr> <th>Balance</th> <td colSpan={2}> <Text type="danger">{totalBorrow - totalRepayment}</Text> </td> </tr> </> ); }} /> <br /> <Table<NestDataType> columns={columnsNest} expandable={{ expandedRowRender }} dataSource={nestDataSource} /> <Table<FixedDataType> columns={columnsFixed} dataSource={fixedDataSource} scroll={{ x: 1300, y: 100 }} /> <Card hoverable style={{ width: 240 }} cover={ <img draggable={false} alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" /> } > <Meta title="Europe Street beat" description="www.instagram.com" /> </Card> <Slider defaultValue={30} /> <DatePicker defaultValue={dayjs('2015/01/01', 'YYYY/MM/DD')} format="YYYY/MM/DD" /> <Badge count={5}> <a href="#" className="head-example" /> </Badge> </Modal> </> ); }; export default Demo; ``` ### 自定义页脚按钮属性 传入 `okButtonProps` 和 `cancelButtonProps` 可分别自定义确定按钮和取消按钮的 props。 ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [open, setOpen] = useState(false); const showModal = () => { setOpen(true); }; const handleOk = (e: React.MouseEvent<HTMLElement>) => { console.log(e); setOpen(false); }; const handleCancel = (e: React.MouseEvent<HTMLElement>) => { console.log(e); setOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal with customized button props </Button> <Modal title="Basic Modal" open={open} onOk={handleOk} onCancel={handleCancel} okButtonProps={{ disabled: true }} cancelButtonProps={{ disabled: true }} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 自定义渲染对话框 自定义渲染对话框, 可通过 `react-draggable` 来实现拖拽。 ```tsx import React, { useRef, useState } from 'react'; import { Button, Modal } from 'antd'; import type { DraggableData, DraggableEvent } from 'react-draggable'; import Draggable from 'react-draggable'; const App: React.FC = () => { const [open, setOpen] = useState(false); const [disabled, setDisabled] = useState(true); const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 }); const draggleRef = useRef<HTMLDivElement>(null!); const showModal = () => { setOpen(true); }; const handleOk = (e: React.MouseEvent<HTMLElement>) => { console.log(e); setOpen(false); }; const handleCancel = (e: React.MouseEvent<HTMLElement>) => { console.log(e); setOpen(false); }; const onStart = (_event: DraggableEvent, uiData: DraggableData) => { const { clientWidth, clientHeight } = window.document.documentElement; const targetRect = draggleRef.current?.getBoundingClientRect(); if (!targetRect) { return; } setBounds({ left: -targetRect.left + uiData.x, right: clientWidth - (targetRect.right - uiData.x), top: -targetRect.top + uiData.y, bottom: clientHeight - (targetRect.bottom - uiData.y), }); }; return ( <> <Button onClick={showModal}>Open Draggable Modal</Button> <Modal title={ <div style={{ width: '100%', cursor: 'move' }} onMouseOver={() => { if (disabled) { setDisabled(false); } }} onMouseOut={() => { setDisabled(true); }} // fix eslintjsx-a11y/mouse-events-have-key-events // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md onFocus={() => {}} onBlur={() => {}} // end > Draggable Modal </div> } open={open} onOk={handleOk} onCancel={handleCancel} modalRender={(modal) => ( <Draggable disabled={disabled} bounds={bounds} nodeRef={draggleRef} onStart={(event, uiData) => onStart(event, uiData)} > <div ref={draggleRef}>{modal}</div> </Draggable> )} > <p> Just don&apos;t learn physics at school and your life will be full of magic and miracles. </p> <br /> <p>Day before yesterday I saw a rabbit, and yesterday a deer, and today, you.</p> </Modal> </> ); }; export default App; ``` ### 自定义模态的宽度 使用 `width` 来设置模态对话框的宽度。 ```tsx import React, { useState } from 'react'; import { Button, Flex, Modal } from 'antd'; const App: React.FC = () => { const [open, setOpen] = useState(false); const [openResponsive, setOpenResponsive] = useState(false); return ( <Flex vertical gap="middle" align="flex-start"> {/* Basic */} <Button type="primary" onClick={() => setOpen(true)}> Open Modal of 1000px width </Button> <Modal title="Modal 1000px width" centered open={open} onOk={() => setOpen(false)} onCancel={() => setOpen(false)} width={1000} > <p>some contents...</p> <p>some contents...</p> <p>some contents...</p> </Modal> {/* Responsive */} <Button type="primary" onClick={() => setOpenResponsive(true)}> Open Modal of responsive width </Button> <Modal title="Modal responsive width" centered open={openResponsive} onOk={() => setOpenResponsive(false)} onCancel={() => setOpenResponsive(false)} width={{ xs: '90%', sm: '80%', md: '70%', lg: '60%', xl: '50%', xxl: '40%', }} > <p>some contents...</p> <p>some contents...</p> <p>some contents...</p> </Modal> </Flex> ); }; export default App; ``` ### 静态方法 静态方法无法消费 Context,不能动态响应 ConfigProvider 提供的各项配置,启用 `layer` 时还可能导致样式异常。请优先使用 hooks 版本或者 App 组件提供的 `modal` 实例。 ```tsx import React from 'react'; import { Button, Modal, Space } from 'antd'; const info = () => { Modal.info({ title: 'This is a notification message', content: ( <div> <p>some messages...some messages...</p> <p>some messages...some messages...</p> </div> ), onOk() {}, }); }; const success = () => { Modal.success({ content: 'some messages...some messages...', }); }; const error = () => { Modal.error({ title: 'This is an error message', content: 'some messages...some messages...', }); }; const warning = () => { Modal.warning({ title: 'This is a warning message', content: 'some messages...some messages...', }); }; const App: React.FC = () => ( <Space wrap> <Button onClick={info}>Info</Button> <Button onClick={success}>Success</Button> <Button onClick={error}>Error</Button> <Button onClick={warning}>Warning</Button> </Space> ); export default App; ``` ### 静态确认对话框 使用 `confirm()` 可以快捷地弹出确认框。onCancel/onOk 返回 promise 可以延迟关闭。 ```tsx import React from 'react'; import { ExclamationCircleFilled } from '@ant-design/icons'; import { Button, Modal, Space } from 'antd'; const { confirm } = Modal; const showConfirm = () => { confirm({ title: 'Do you want to delete these items?', icon: <ExclamationCircleFilled />, content: 'Some descriptions', onOk() { console.log('OK'); }, onCancel() { console.log('Cancel'); }, }); }; const showPromiseConfirm = () => { confirm({ title: 'Do you want to delete these items?', icon: <ExclamationCircleFilled />, content: 'When clicked the OK button, this dialog will be closed after 1 second', onOk() { return new Promise((resolve, reject) => { setTimeout(Math.random() > 0.5 ? resolve : reject, 1000); }).catch(() => console.log('Oops errors!')); }, onCancel() {}, }); }; const showDeleteConfirm = () => { confirm({ title: 'Are you sure delete this task?', icon: <ExclamationCircleFilled />, content: 'Some descriptions', okText: 'Yes', okType: 'danger', cancelText: 'No', onOk() { console.log('OK'); }, onCancel() { console.log('Cancel'); }, }); }; const showPropsConfirm = () => { confirm({ title: 'Are you sure delete this task?', icon: <ExclamationCircleFilled />, content: 'Some descriptions', okText: 'Yes', okType: 'danger', okButtonProps: { disabled: true, }, cancelText: 'No', onOk() { console.log('OK'); }, onCancel() { console.log('Cancel'); }, }); }; const App: React.FC = () => ( <Space wrap> <Button onClick={showConfirm}>Confirm</Button> <Button onClick={showPromiseConfirm}>With promise</Button> <Button onClick={showDeleteConfirm} type="dashed"> Delete </Button> <Button onClick={showPropsConfirm} type="dashed"> With extra props </Button> </Space> ); export default App; ``` ### 自定义内部模块 className 通过 `classNames` 属性设置弹窗内部区域(header、body、footer、mask、wrapper)的 `className`。 ```tsx import React, { useState } from 'react'; import { Button, ConfigProvider, Modal, Space } from 'antd'; import { createStyles, useTheme } from 'antd-style'; const useStyle = createStyles(({ token }) => ({ 'my-modal-body': { background: token.blue1, padding: token.paddingSM, }, 'my-modal-mask': { boxShadow: `inset 0 0 15px #fff`, }, 'my-modal-header': { borderBottom: `1px dotted ${token.colorPrimary}`, }, 'my-modal-footer': { color: token.colorPrimary, }, 'my-modal-content': { border: '1px solid #333', }, })); const App: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState([false, false]); const { styles } = useStyle(); const token = useTheme(); const toggleModal = (idx: number, target: boolean) => { setIsModalOpen((p) => { p[idx] = target; return [...p]; }); }; const classNames = { body: styles['my-modal-body'], mask: styles['my-modal-mask'], header: styles['my-modal-header'], footer: styles['my-modal-footer'], content: styles['my-modal-content'], }; const modalStyles = { header: { borderInlineStart: `5px solid ${token.colorPrimary}`, borderRadius: 0, paddingInlineStart: 5, }, body: { boxShadow: 'inset 0 0 5px #999', borderRadius: 5, }, mask: { backdropFilter: 'blur(10px)', }, footer: { borderTop: '1px solid #333', }, content: { boxShadow: '0 0 30px #999', }, }; return ( <> <Space> <Button type="primary" onClick={() => toggleModal(0, true)}> Open Modal </Button> <Button type="primary" onClick={() => toggleModal(1, true)}> ConfigProvider </Button> </Space> <Modal title="Basic Modal" open={isModalOpen[0]} onOk={() => toggleModal(0, false)} onCancel={() => toggleModal(0, false)} footer="Footer" classNames={classNames} styles={modalStyles} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> <ConfigProvider modal={{ classNames, styles: modalStyles, }} > <Modal title="Basic Modal" open={isModalOpen[1]} onOk={() => toggleModal(1, false)} onCancel={() => toggleModal(1, false)} footer="Footer" > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </ConfigProvider> </> ); }; export default App; ``` ### 销毁确认对话框 使用 `Modal.destroyAll()` 可以销毁弹出的确认窗。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题。 ```tsx import React from 'react'; import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Button, Modal } from 'antd'; const { confirm } = Modal; const destroyAll = () => { Modal.destroyAll(); }; const showConfirm = () => { for (let i = 0; i < 3; i += 1) { setTimeout(() => { confirm({ icon: <ExclamationCircleOutlined />, content: <Button onClick={destroyAll}>Click to destroy all</Button>, onOk() { console.log('OK'); }, onCancel() { console.log('Cancel'); }, }); }, i * 500); } }; const App: React.FC = () => <Button onClick={showConfirm}>Confirm</Button>; export default App; ``` ### 嵌套弹框 嵌套弹框 ```tsx import React, { useState } from 'react'; import { Button, message, Modal, notification, Select, Space, Switch } from 'antd'; const options = [ { label: 'Option 1', value: '1', }, { label: 'Option 2', value: '2', }, ]; const Demo: React.FC = () => { const [messageInstance, messageHolder] = message.useMessage(); const [notificationInstance, notificationHolder] = notification.useNotification(); const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const onShowStatic = () => { Modal.confirm({ content: <Select open value="1" options={options} />, }); }; return ( <Space> <Switch style={{ position: 'relative', zIndex: isModalOpen ? 4000 : 0 }} checkedChildren="Open" unCheckedChildren="Close" onChange={(open) => setIsModalOpen(open)} /> <Button onClick={onShowStatic}>Static</Button> <Modal title="Basic Modal" open={isModalOpen} footer={null} destroyOnHidden onCancel={() => setIsModalOpen(false)} maskClosable={false} closable={false} styles={{ content: { marginBlockStart: 100, }, }} > <Select open value="1" options={options} /> <Modal title="Nested Modal" open={isModalOpen} footer={null} destroyOnHidden mask={false} onCancel={() => setIsModalOpen(false)} maskClosable={false} closable={false} styles={{ content: { marginBlockStart: 250, }, body: { display: 'flex', justifyContent: 'center', }, }} > <Select open value="1" options={options} /> <Modal title="Nested Modal" open={isModalOpen} footer={null} destroyOnHidden mask={false} maskClosable={false} onCancel={() => setIsModalOpen(false)} closable={false} styles={{ content: { marginBlockStart: 400, }, body: { display: 'flex', justifyContent: 'flex-end', }, }} > <Space wrap> <Button onClick={() => { Modal.confirm({ title: 'Are you OK?', content: 'I am OK', }); }} > Static Confirm </Button> <Button onClick={() => { message.success('Hello World'); notification.success({ message: 'Hello World', }); }} > Static Message, Notification </Button> <Button onClick={() => { messageInstance.success('Hello World'); notificationInstance.success({ message: 'Hello World', }); }} > Hook Message, Notification </Button> <Select open value="1" options={options} /> </Space> </Modal> </Modal> </Modal> {messageHolder} {notificationHolder} </Space> ); }; export default Demo; ``` ### \_InternalPanelDoNotUseOrYouWillBeFired 调试用组件,请勿直接使用。 ```tsx import React from 'react'; import { Button, Modal, Space, Typography } from 'antd'; import type { ModalFuncProps } from 'antd'; /** Test usage. Do not use in your production. */ const { _InternalPanelDoNotUseOrYouWillBeFired: InternalPanel } = Modal; const customFooterFn: ModalFuncProps['footer'] = (originNode, { OkBtn, CancelBtn }) => ( <Space direction="vertical"> <Space>{originNode}</Space> <Space> <CancelBtn /> <Button danger type="primary"> Custom </Button> <OkBtn /> </Space> </Space> ); export default () => ( <div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}> <InternalPanel title="Hello World!" style={{ width: '100%', height: 200 }}> Hello World?! </InternalPanel> <InternalPanel type="success" style={{ width: 200, height: 150 }}> A good news! </InternalPanel> <InternalPanel title="Confirm This?" type="confirm" style={{ width: 300, height: 200 }}> Some descriptions. </InternalPanel> <InternalPanel title="Custom Footer Render" style={{ width: 380, height: 200 }} footer={customFooterFn} > <Typography.Paragraph> <Typography.Link href="https://github.com/ant-design/ant-design/pull/44318"> Feature #44318 </Typography.Link> </Typography.Paragraph> </InternalPanel> </div> ); ``` ### 控制弹框动画原点 通过 `mousePosition` 控制弹框动画原点. ```tsx import React, { useState } from 'react'; import { Button, Modal } from 'antd'; const App: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const showModal = () => { setIsModalOpen(true); }; const handleOk = () => { setIsModalOpen(false); }; const handleCancel = () => { setIsModalOpen(false); }; return ( <> <Button type="primary" onClick={showModal}> Open Modal </Button> <Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel} mousePosition={{ x: 300, y: 300 }} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </> ); }; export default App; ``` ### 线框风格 线框风格。 ```tsx import React from 'react'; import { ConfigProvider, Modal } from 'antd'; /** Test usage. Do not use in your production. */ const { _InternalPanelDoNotUseOrYouWillBeFired: InternalPanel } = Modal; export default () => ( <ConfigProvider theme={{ token: { wireframe: true } }}> <div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}> <InternalPanel title="Hello World!" style={{ width: '100%' }}> Hello World?! </InternalPanel> <InternalPanel type="success" style={{ width: 200 }}> A good news! </InternalPanel> <InternalPanel title="Confirm This?" type="confirm" style={{ width: 300 }}> Some descriptions. </InternalPanel> </div> </ConfigProvider> ); ``` ### 组件 Token Component Token Debug. ```tsx import React from 'react'; import { ConfigProvider, Modal } from 'antd'; /** Test usage. Do not use in your production. */ const { _InternalPanelDoNotUseOrYouWillBeFired: InternalPanel } = Modal; export default () => ( <ConfigProvider theme={{ components: { Modal: { footerBg: '#f6ffed', contentBg: '#e6fffb', headerBg: '#f9f0ff', titleLineHeight: 3, titleFontSize: 12, titleColor: '#1d39c4', }, }, }} > <div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}> <InternalPanel title="Hello World!" style={{ width: '100%' }}> Hello World?! </InternalPanel> <ConfigProvider theme={{ token: { wireframe: true } }}> <InternalPanel title="Hello World!" style={{ width: '100%' }}> Hello World?! </InternalPanel> </ConfigProvider> <InternalPanel type="success" style={{ width: 200 }}> A good news! </InternalPanel> <InternalPanel title="Confirm This?" type="confirm" style={{ width: 300 }}> Some descriptions. </InternalPanel> </div> </ConfigProvider> ); ```

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zhixiaoqiang/antd-components-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server