@refinedev/antd package offers pre-built components that seamlessly integrate with Refine’s core functionality.
Installation
npm install @refinedev/antd antd @ant-design/icons dayjs
Setup
Basic Setup
Wrap your application with Ant Design’s theme provider and use Refine’s themed layout:App.tsx
import { Refine } from "@refinedev/core";
import {
ThemedLayout,
RefineThemes,
useNotificationProvider,
} from "@refinedev/antd";
import { ConfigProvider, App as AntdApp } from "antd";
import dataProvider from "@refinedev/simple-rest";
import "@refinedev/antd/dist/reset.css";
function App() {
return (
<ConfigProvider theme={RefineThemes.Blue}>
<AntdApp>
<Refine
dataProvider={dataProvider("https://api.example.com")}
notificationProvider={useNotificationProvider}
resources={[
{
name: "products",
list: "/products",
create: "/products/create",
edit: "/products/edit/:id",
show: "/products/show/:id",
},
]}
>
<ThemedLayout>
{/* Your pages here */}
</ThemedLayout>
</Refine>
</AntdApp>
</ConfigProvider>
);
}
export default App;
Available Themes
Refine provides pre-configured Ant Design themes:import { RefineThemes } from "@refinedev/antd";
// Available themes:
RefineThemes.Blue
RefineThemes.Purple
RefineThemes.Magenta
RefineThemes.Red
RefineThemes.Orange
RefineThemes.Yellow
Custom Theme
You can customize the theme using Ant Design’s theme configuration:import { ConfigProvider, theme } from "antd";
function App() {
return (
<ConfigProvider
theme={{
algorithm: theme.darkAlgorithm,
token: {
colorPrimary: "#1890ff",
borderRadius: 8,
},
}}
>
{/* Your app */}
</ConfigProvider>
);
}
Layout Components
ThemedLayout
The main layout component with sidebar, header, and content area:import { ThemedLayout } from "@refinedev/antd";
function App() {
return (
<Refine
// ... other props
>
<ThemedLayout>
{/* Your routes */}
</ThemedLayout>
</Refine>
);
}
Custom Layout Components
You can customize individual layout components:import {
ThemedLayout,
ThemedSider,
ThemedHeader,
ThemedTitle,
} from "@refinedev/antd";
function App() {
return (
<ThemedLayout
Sider={() => <ThemedSider fixed />}
Header={() => <ThemedHeader sticky />}
Title={({ collapsed }) => (
<ThemedTitle collapsed={collapsed} text="My Admin" />
)}
>
{/* Your routes */}
</ThemedLayout>
);
}
CRUD Components
List
Display list of records with automatic page header and create button:pages/products/list.tsx
import { List, useTable, EditButton, ShowButton } from "@refinedev/antd";
import { Table, Space } from "antd";
export const ProductList = () => {
const { tableProps } = useTable();
return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" />
<Table.Column dataIndex="name" title="Name" />
<Table.Column dataIndex="price" title="Price" />
<Table.Column
title="Actions"
render={(_, record) => (
<Space>
<EditButton size="small" recordItemId={record.id} />
<ShowButton size="small" recordItemId={record.id} />
</Space>
)}
/>
</Table>
</List>
);
};
Create
Create form with automatic save button and navigation:pages/products/create.tsx
import { Create, useForm } from "@refinedev/antd";
import { Form, Input, InputNumber } from "antd";
export const ProductCreate = () => {
const { formProps, saveButtonProps } = useForm();
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Name"
name="name"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Price"
name="price"
rules={[{ required: true }]}
>
<InputNumber style={{ width: "100%" }} />
</Form.Item>
<Form.Item label="Description" name="description">
<Input.TextArea rows={4} />
</Form.Item>
</Form>
</Create>
);
};
Edit
Edit form with automatic data fetching and save button:pages/products/edit.tsx
import { Edit, useForm } from "@refinedev/antd";
import { Form, Input, InputNumber } from "antd";
export const ProductEdit = () => {
const { formProps, saveButtonProps, queryResult } = useForm();
return (
<Edit saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="ID" name="id">
<Input disabled />
</Form.Item>
<Form.Item
label="Name"
name="name"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Price"
name="price"
rules={[{ required: true }]}
>
<InputNumber style={{ width: "100%" }} />
</Form.Item>
</Form>
</Edit>
);
};
Show
Display single record in read-only mode:pages/products/show.tsx
import {
Show,
TextField,
NumberField,
DateField,
} from "@refinedev/antd";
import { useShow } from "@refinedev/core";
import { Typography } from "antd";
const { Title } = Typography;
export const ProductShow = () => {
const { queryResult } = useShow();
const { data, isLoading } = queryResult;
const record = data?.data;
return (
<Show isLoading={isLoading}>
<Title level={5}>ID</Title>
<TextField value={record?.id} />
<Title level={5}>Name</Title>
<TextField value={record?.name} />
<Title level={5}>Price</Title>
<NumberField
value={record?.price}
options={{
style: "currency",
currency: "USD",
}}
/>
<Title level={5}>Created At</Title>
<DateField value={record?.createdAt} />
</Show>
);
};
Field Components
Refine provides field components for displaying different types of data:import {
TextField,
NumberField,
DateField,
EmailField,
UrlField,
BooleanField,
TagField,
ImageField,
FileField,
MarkdownField,
} from "@refinedev/antd";
import { Space } from "antd";
function FieldExamples() {
return (
<Space direction="vertical">
<TextField value="Simple text" />
<NumberField
value={1234.56}
options={{ style: "currency", currency: "USD" }}
/>
<DateField value="2024-01-15" format="LLL" />
<EmailField value="[email protected]" />
<UrlField value="https://example.com" />
<BooleanField value={true} />
<TagField value="Active" color="green" />
<ImageField value="https://example.com/image.jpg" width={200} />
<FileField src="https://example.com/file.pdf" title="Download" />
<MarkdownField value="# Hello\n\nThis is **markdown**" />
</Space>
);
}
Button Components
Refine provides action buttons with automatic routing and confirmation:import {
CreateButton,
EditButton,
ShowButton,
DeleteButton,
ListButton,
RefreshButton,
SaveButton,
CloneButton,
ExportButton,
ImportButton,
} from "@refinedev/antd";
import { Space } from "antd";
function ButtonExamples() {
return (
<Space>
<CreateButton resource="products" />
<EditButton resource="products" recordItemId="1" />
<ShowButton resource="products" recordItemId="1" />
<DeleteButton resource="products" recordItemId="1" />
<ListButton resource="products" />
<RefreshButton resource="products" />
<SaveButton />
<CloneButton resource="products" recordItemId="1" />
<ExportButton />
<ImportButton />
</Space>
);
}
Advanced Features
Data Grid with Filters
import { List, useTable, FilterDropdown } from "@refinedev/antd";
import { Table, Input, Select, DatePicker } from "antd";
import { SearchOutlined } from "@ant-design/icons";
export const ProductList = () => {
const { tableProps, filters, sorters } = useTable({
initialSorter: [
{
field: "id",
order: "desc",
},
],
});
return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column
dataIndex="name"
title="Name"
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Input placeholder="Search name" />
</FilterDropdown>
)}
filterIcon={<SearchOutlined />}
/>
<Table.Column
dataIndex="status"
title="Status"
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Select
style={{ width: 200 }}
placeholder="Select status"
options={[
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" },
]}
/>
</FilterDropdown>
)}
/>
<Table.Column
dataIndex="price"
title="Price"
sorter
/>
</Table>
</List>
);
};
Modal Forms
import { useModalForm, CreateButton, Edit } from "@refinedev/antd";
import { Modal, Form, Input } from "antd";
export const ProductList = () => {
const { modalProps, formProps, show } = useModalForm({
action: "create",
});
return (
<>
<CreateButton onClick={() => show()} />
<Modal {...modalProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Modal>
</>
);
};
Drawer Forms
import { useDrawerForm, EditButton } from "@refinedev/antd";
import { Drawer, Form, Input } from "antd";
export const ProductList = () => {
const { drawerProps, formProps, show } = useDrawerForm({
action: "edit",
});
return (
<>
<EditButton onClick={() => show("1")} />
<Drawer {...drawerProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Drawer>
</>
);
};
Auto-Save Indicator
import { AutoSaveIndicator, useForm } from "@refinedev/antd";
import { Form, Input } from "antd";
export const ProductEdit = () => {
const { formProps, autoSaveProps } = useForm({
autoSave: {
enabled: true,
debounce: 2000,
},
});
return (
<>
<AutoSaveIndicator {...autoSaveProps} />
<Form {...formProps} layout="vertical">
<Form.Item label="Name" name="name">
<Input />
</Form.Item>
</Form>
</>
);
};
Pro Layout
Refine integrates with Ant Design Pro Layout for advanced layouts:import { ThemedLayout } from "@refinedev/antd";
// Pro Layout is automatically used in ThemedLayout
// It provides:
// - Collapsible sidebar
// - Responsive design
// - Breadcrumb navigation
// - Multiple menu modes
Next Steps
Ant Design Docs
Official Ant Design documentation
Examples
See complete Ant Design examples
Hooks
Learn about Refine hooks
Theming
Customize your theme