Overview
ProComponents is built on Ant Design’s Design Token system, providing powerful customization capabilities while maintaining design consistency. This guide covers styling, theming, and extending components.Theme Customization
Using ProConfigProvider
TheProConfigProvider wraps your application and provides theme configuration to all ProComponents.
import { ProConfigProvider } from '@ant-design/pro-components';
import { ConfigProvider } from 'antd';
function App() {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: '#00b96b',
},
}}
>
<ProConfigProvider
token={{
layout: {
sider: {
colorMenuBackground: '#001529',
colorTextMenu: '#fff',
},
},
}}
>
<YourApp />
</ProConfigProvider>
</ConfigProvider>
);
}
Always wrap
ProConfigProvider inside Ant Design’s ConfigProvider to ensure proper theme inheritance.Design Tokens
Brand Colors
Customize your application’s primary colors:import { ConfigProvider } from 'antd';
const theme = {
token: {
colorPrimary: '#1890ff', // Primary brand color
colorSuccess: '#52c41a', // Success state
colorWarning: '#faad14', // Warning state
colorError: '#f5222d', // Error state
colorInfo: '#1890ff', // Info state
},
};
<ConfigProvider theme={theme}>
<App />
</ConfigProvider>
Layout Tokens
ProComponents provides specific tokens for layout customization:import { ProConfigProvider } from '@ant-design/pro-components';
const layoutToken = {
layout: {
// Sider (sidebar) customization
sider: {
colorMenuBackground: '#001529', // Sidebar background
colorTextMenu: 'rgba(255, 255, 255, 0.65)', // Menu text color
colorTextMenuSelected: '#fff', // Selected menu text
colorBgMenuItemSelected: '#1890ff', // Selected menu background
colorBgMenuItemHover: 'rgba(255, 255, 255, 0.08)', // Hover background
paddingInlineLayoutMenu: 8, // Menu horizontal padding
paddingBlockLayoutMenu: 0, // Menu vertical padding
},
// Header customization
header: {
colorBgHeader: '#001529', // Header background
colorHeaderTitle: '#fff', // Header title color
colorTextMenu: 'rgba(255, 255, 255, 0.65)', // Header menu text
heightLayoutHeader: 56, // Header height
},
// Page container customization
pageContainer: {
colorBgPageContainer: 'transparent', // Container background
paddingInlinePageContainerContent: 40, // Horizontal padding
paddingBlockPageContainerContent: 32, // Vertical padding
},
},
};
<ProConfigProvider token={layoutToken}>
<App />
</ProConfigProvider>
Dark Mode
Enable dark mode using thedark prop:
import { ProConfigProvider } from '@ant-design/pro-components';
import { useState } from 'react';
function App() {
const [isDark, setIsDark] = useState(false);
return (
<ProConfigProvider dark={isDark}>
<Switch
checked={isDark}
onChange={setIsDark}
checkedChildren="🌙"
unCheckedChildren="☀️"
/>
<YourApp />
</ProConfigProvider>
);
}
Dark mode automatically adjusts all ProComponents colors using Ant Design’s dark algorithm.
Component Customization
ProTable Customization
Custom Column Rendering
import { ProTable } from '@ant-design/pro-components';
import { Tag, Avatar, Space } from 'antd';
const columns = [
{
title: 'User',
dataIndex: 'name',
render: (text, record) => (
<Space>
<Avatar src={record.avatar} />
<span>{text}</span>
</Space>
),
},
{
title: 'Status',
dataIndex: 'status',
render: (status) => {
const color = status === 'active' ? 'green' : 'red';
return <Tag color={color}>{status.toUpperCase()}</Tag>;
},
},
];
<ProTable columns={columns} {...otherProps} />
Custom Toolbar
import { ProTable } from '@ant-design/pro-components';
import { Button, Dropdown } from 'antd';
import { PlusOutlined, DownloadOutlined } from '@ant-design/icons';
<ProTable
headerTitle="User List"
toolBarRender={() => [
<Button key="create" type="primary" icon={<PlusOutlined />}>
Create New
</Button>,
<Dropdown
key="export"
menu={{
items: [
{ key: 'csv', label: 'Export as CSV' },
{ key: 'excel', label: 'Export as Excel' },
],
}}
>
<Button icon={<DownloadOutlined />}>Export</Button>
</Dropdown>,
]}
/>
Custom Search Form
import { ProTable } from '@ant-design/pro-components';
<ProTable
search={{
labelWidth: 'auto',
span: 8, // Grid column span
defaultCollapsed: false, // Show expanded by default
optionRender: (searchConfig, formProps, dom) => [
...dom.reverse(), // Reverse button order
<Button key="custom">Custom Action</Button>,
],
}}
/>
ProForm Customization
Custom Form Layout
import { ProForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
<ProForm
layout="horizontal"
grid={true}
colProps={{
xs: 24,
sm: 12,
md: 8,
}}
submitter={{
render: (props, doms) => {
return [
<Button key="reset" onClick={() => props.form?.resetFields()}>
Reset
</Button>,
<Button key="submit" type="primary" onClick={() => props.form?.submit()}>
Submit
</Button>,
];
},
}}
>
<ProFormText name="name" label="Name" />
<ProFormSelect name="type" label="Type" />
</ProForm>
Custom Field Components
Create reusable custom field components:import { ProForm, ProFormField } from '@ant-design/pro-components';
import { Input, Space, Button } from 'antd';
import { PlusOutlined, MinusOutlined } from '@ant-design/icons';
const QuantityField = ({ value, onChange }) => {
return (
<Space>
<Button
icon={<MinusOutlined />}
onClick={() => onChange(Math.max(0, (value || 0) - 1))}
/>
<Input
value={value}
onChange={(e) => onChange(parseInt(e.target.value) || 0)}
style={{ width: 60, textAlign: 'center' }}
/>
<Button
icon={<PlusOutlined />}
onClick={() => onChange((value || 0) + 1)}
/>
</Space>
);
};
<ProForm>
<ProFormField
name="quantity"
label="Quantity"
>
<QuantityField />
</ProFormField>
</ProForm>
ProLayout Customization
Custom Menu Items
import { ProLayout } from '@ant-design/pro-components';
import { DashboardOutlined, UserOutlined } from '@ant-design/icons';
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
icon: <DashboardOutlined />,
},
{
path: '/users',
name: 'Users',
icon: <UserOutlined />,
routes: [
{
path: '/users/list',
name: 'User List',
},
{
path: '/users/groups',
name: 'User Groups',
},
],
},
];
<ProLayout
route={{ routes }}
menuItemRender={(item, dom) => (
<a onClick={() => navigate(item.path)}>{dom}</a>
)}
/>
Custom Header Content
import { ProLayout } from '@ant-design/pro-components';
import { Input, Badge, Avatar, Dropdown } from 'antd';
import { SearchOutlined, BellOutlined, SettingOutlined } from '@ant-design/icons';
<ProLayout
headerContentRender={() => (
<Input
prefix={<SearchOutlined />}
placeholder="Search..."
style={{ width: 300 }}
/>
)}
actionsRender={() => [
<Badge key="notifications" count={5}>
<BellOutlined style={{ fontSize: 18 }} />
</Badge>,
<SettingOutlined key="settings" style={{ fontSize: 18 }} />,
]}
avatarProps={{
src: 'https://avatars.githubusercontent.com/u/8186664?v=4',
title: 'John Doe',
render: (props, dom) => (
<Dropdown
menu={{
items: [
{ key: 'profile', label: 'Profile' },
{ key: 'settings', label: 'Settings' },
{ type: 'divider' },
{ key: 'logout', label: 'Logout' },
],
}}
>
{dom}
</Dropdown>
),
}}
/>
Styling with CSS-in-JS
Using useToken Hook
Access design tokens in your custom components:import { theme } from 'antd';
import { useToken } from '@ant-design/pro-components';
const CustomCard = () => {
const { token } = theme.useToken();
return (
<div
style={{
backgroundColor: token.colorBgContainer,
border: `1px solid ${token.colorBorder}`,
borderRadius: token.borderRadius,
padding: token.padding,
boxShadow: token.boxShadow,
}}
>
Custom Card Content
</div>
);
};
Emotion CSS
ProComponents uses Emotion for CSS-in-JS:import { css } from '@emotion/css';
import { theme } from 'antd';
const useStyles = () => {
const { token } = theme.useToken();
return {
container: css`
background-color: ${token.colorBgContainer};
padding: ${token.paddingLG}px;
border-radius: ${token.borderRadius}px;
&:hover {
box-shadow: ${token.boxShadowSecondary};
}
`,
title: css`
color: ${token.colorText};
font-size: ${token.fontSizeLG}px;
font-weight: ${token.fontWeightStrong};
margin-bottom: ${token.marginMD}px;
`,
};
};
const MyComponent = () => {
const styles = useStyles();
return (
<div className={styles.container}>
<h2 className={styles.title}>Title</h2>
<p>Content</p>
</div>
);
};
CSS Variables
ProComponents supports CSS variables for dynamic theming:import { ProConfigProvider } from '@ant-design/pro-components';
<ProConfigProvider
token={{
layout: {
sider: {
colorMenuBackground: 'var(--sidebar-bg)',
colorTextMenu: 'var(--sidebar-text)',
},
},
}}
>
<App />
</ProConfigProvider>
/* Your CSS file */
:root {
--sidebar-bg: #001529;
--sidebar-text: rgba(255, 255, 255, 0.65);
}
[data-theme='light'] {
--sidebar-bg: #ffffff;
--sidebar-text: rgba(0, 0, 0, 0.65);
}
Internationalization (i18n)
Configure Locale
import { ProConfigProvider } from '@ant-design/pro-components';
import { ConfigProvider } from 'antd';
import enUS from 'antd/locale/en_US';
import zhCN from 'antd/locale/zh_CN';
function App() {
const [locale, setLocale] = useState('en-US');
return (
<ConfigProvider locale={locale === 'en-US' ? enUS : zhCN}>
<ProConfigProvider>
<YourApp />
</ProConfigProvider>
</ConfigProvider>
);
}
Custom Intl Messages
import { ProConfigProvider, createIntl } from '@ant-design/pro-components';
const customIntl = createIntl('en-US', {
tableForm: {
search: 'Find',
reset: 'Clear',
submit: 'Search Now',
},
});
<ProConfigProvider intl={customIntl}>
<App />
</ProConfigProvider>
Advanced Customization
Extending Components
Create wrapped components with custom defaults:import { ProTable } from '@ant-design/pro-components';
import type { ProTableProps } from '@ant-design/pro-components';
function MyProTable<T extends Record<string, any>>(
props: ProTableProps<T, any>
) {
return (
<ProTable<T>
search={{
labelWidth: 'auto',
defaultCollapsed: false,
...props.search,
}}
pagination={{
pageSize: 20,
showSizeChanger: true,
...props.pagination,
}}
options={{
density: true,
fullScreen: true,
reload: true,
setting: true,
...props.options,
}}
{...props}
/>
);
}
export default MyProTable;
Global Styles
Apply global customizations using CSS:/* Override specific ProComponents styles */
.ant-pro-table-search {
background-color: #fafafa;
padding: 24px;
border-radius: 8px;
}
.ant-pro-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.ant-pro-page-container-children-content {
margin: 24px;
}
Use global CSS overrides sparingly. Prefer using design tokens and component props for maintainable customizations.
Best Practices
Use Design Tokens
Always use design tokens instead of hardcoded values for colors, spacing, and typography:
// ✅ Good
const { token } = theme.useToken();
style={{ padding: token.padding }}
// ❌ Avoid
style={{ padding: '16px' }}
Maintain Theme Consistency
Keep all theme customizations in a centralized location:
// theme/index.ts
export const themeConfig = {
token: { /* tokens */ },
components: { /* component overrides */ },
};
Test in Both Light and Dark Modes
Always verify your customizations work in both themes:
// Test component in both modes
<ProConfigProvider dark={false}>
<YourComponent />
</ProConfigProvider>
<ProConfigProvider dark={true}>
<YourComponent />
</ProConfigProvider>
Examples
Complete Theme Configuration
import { ProConfigProvider } from '@ant-design/pro-components';
import { ConfigProvider } from 'antd';
const App = () => {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: '#1677ff',
borderRadius: 6,
fontSize: 14,
},
components: {
Button: {
controlHeight: 32,
},
Table: {
headerBg: '#fafafa',
},
},
}}
>
<ProConfigProvider
dark={false}
token={{
layout: {
sider: {
colorMenuBackground: '#001529',
colorTextMenu: 'rgba(255, 255, 255, 0.65)',
colorTextMenuSelected: '#fff',
colorBgMenuItemSelected: '#1677ff',
},
header: {
colorBgHeader: '#001529',
heightLayoutHeader: 64,
},
},
}}
hashed={false}
>
<YourApp />
</ProConfigProvider>
</ConfigProvider>
);
};
Check the Ant Design Theme Editor to visually design your theme and export the configuration.