with one click
frontend-antd-components
// Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal)
// Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal)
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | frontend-antd-components |
| description | Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal) |
All new components must use Ant Design (ANTD) with theme tokens. Never use Radix UI, TailwindCSS, or hardcoded values for new development.
Always use ANTD theme tokens instead of hardcoded values:
import { theme } from 'antd';
function MyComponent() {
const { token } = theme.useToken();
return (
<div style={{
padding: token.paddingXL,
color: token.colorPrimary,
fontSize: token.fontSizeLG,
borderRadius: token.borderRadiusLG,
}}>
Content
</div>
);
}
Common Token Categories:
token.colorPrimary, token.colorError, token.colorSuccess, token.colorBordertoken.paddingSM, token.marginMD, token.paddingLG, token.marginXLtoken.fontSize, token.fontSizeLG, token.fontSizeHeading1token.borderRadius, token.borderRadiusLGUse ANTD Typography components for text content:
import { Typography, theme } from 'antd';
const { Title, Paragraph, Text } = Typography;
function MyComponent() {
const { token } = theme.useToken();
return (
<>
<Title level={1}>Page Title</Title>
<Paragraph type="secondary">Description text</Paragraph>
<Text strong>Bold text</Text>
</>
);
}
Always use App.useApp() hook for feedback components:
import { App } from 'antd';
function MyComponent() {
const { message, notification, modal } = App.useApp();
const handleSuccess = () => {
message.success('Operation successful!');
};
const handleNotify = () => {
notification.info({
message: 'Update Available',
description: 'A new version is ready.',
});
};
return <button onClick={handleSuccess}>Save</button>;
}
Note: Your app must be wrapped with <App> in the provider. See src/providers/antd/Provider_ANTD.tsx.
Always use async onOk with mutateAsync for delete confirmations and critical actions:
import { App } from 'antd';
import { useM_Files_Delete } from "@/hooks/Files/useM_Files_Delete";
function MyComponent() {
const { modal } = App.useApp();
const mFiles_Delete = useM_Files_Delete();
const handleDelete = (fileId: string, fileName: string) => {
modal.confirm({
title: "Delete File",
content: `Are you sure you want to delete "${fileName}"?`,
okText: "Delete",
okType: "danger",
onOk: async () => {
await mFiles_Delete.mutation.mutateAsync({ fileId });
},
});
};
return <button onClick={() => handleDelete('file_1', 'document.pdf')}>Delete</button>;
}
Why async onOk matters:
Primary: Use @ant-design/icons for all icons:
import { PlusOutlined, EditOutlined, ProjectOutlined } from '@ant-design/icons';
function MyComponent() {
const { token } = theme.useToken();
return (
<>
<Button icon={<PlusOutlined />}>Create</Button>
<ProjectOutlined style={{ fontSize: 18, color: token.colorPrimary }} />
</>
);
}
Alternative: Use lucide-react only when ANTD doesn't have a suitable icon. Never mix both in the same component.
Use ANTD Form components with validation rules:
import { Form, Input, Button } from 'antd';
function MyComponent() {
const [form] = Form.useForm();
const handleSubmit = () => {
form.validateFields().then((values) => {
// Handle submission
});
};
return (
<Form form={form} layout="vertical">
<Form.Item
label="Name"
name="name"
rules={[
{ required: true, message: 'Please enter a name' },
{ min: 1, max: 255, message: 'Name must be 1-255 characters' },
]}
>
<Input placeholder="Enter name..." />
</Form.Item>
<Button type="primary" onClick={handleSubmit}>
Submit
</Button>
</Form>
);
}
Some ANTD props are deprecated and cause console warnings. Always use the new replacement props.
Common Deprecated Props:
bodyStyle → ✅ Use styles={{ body: {...} }}destroyOnClose → ✅ Use destroyOnHiddenorientation="left/right" → ✅ Use titlePlacement="left/right" (for text positioning)Examples:
// ✅ Good - Use styles.body
<Card styles={{ body: { padding: token.paddingSM } }}>Content</Card>
// ✅ Good - Use destroyOnHidden
<Modal destroyOnHidden>Content</Modal>
// ✅ Good - Use titlePlacement for text positioning
<Divider titlePlacement="left">Section Title</Divider>
Button and other components have component-level tokens set in Provider_ANTD.tsx. Do NOT override these with inline styles — use ANTD's size prop and let the tokens handle it:
// ❌ Bad — overrides component tokens with inline styles
<Button type="primary" style={{ borderRadius: 9999, fontSize: 16, fontWeight: 600, paddingInline: 24 }}>
// ✅ Good — component tokens handle radius, font, padding automatically
<Button type="primary" size="large">
Configured Button sizes (via component tokens):
size="large" → 48px height, 16px font, 24px padding, pill shapesize="middle" (default) → 32px height, 12px font, 16px padding, pill shapeCheck for these violations before proceeding:
theme.useToken() and token.*import { message } from 'antd' → ✅ const { message } = App.useApp()<h1>, <p>) → ✅ ANTD Typography (<Title>, <Paragraph>)theme.useToken() hook → ✅ Import and use in component@ant-design/icons)bodyStyle, destroyOnClose, orientation on Divider) → ✅ Use new propssize propIf any violations are detected, point them out and ask the user to confirm before proceeding.
For complete practices: docs/spark/frontend/my-vite-app/practices.md - "UI Component Library"
For detailed examples: .claude/skills/frontend-antd-components/examples.md