Ui Guidelines
ASecurityAnt Design house style for one specific React/Next.js application — its design tokens, color palette, typography scale, 8px/12px/16px/24px spacing, animations, and copy-ready patterns for antd tables, forms in modals, selectable card grids, loading states, avatars, and status tags. Use when building or restyling a form, table, modal, card, list, or page layout in a codebase that already standardizes on Ant Design and the new component must match the existing design system. It is not a general...
- 7 stars
- 0 votes
- 0 copies
- 2 views
- Added October 14, 2026
Works with
Security analysis
100/100Pro scans all 6 files and shows the line behind each finding
npx -y skills add pfangueiro/claude-code-agents --skill ui-guidelines --agent claude-codeAre you the author of Ui Guidelines?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/pfangueiro-ui-guidelines)---
name: ui-guidelines
description: Ant Design house style for one specific React/Next.js application — its design tokens, color palette, typography scale, 8px/12px/16px/24px spacing, animations, and copy-ready patterns for antd tables, forms in modals, selectable card grids, loading states, avatars, and status tags. Use when building or restyling a form, table, modal, card, list, or page layout in a codebase that already standardizes on Ant Design and the new component must match the existing design system. It is not a general UI or accessibility reference, does not apply to Tailwind, Material UI, Chakra, or plain-CSS projects, and carries no chart or data-visualization guidance — charts, graphs, dashboards, and palette choice for data viz are out of scope.
---
# UI Guidelines for Application
## Overview
This skill provides UI/UX guidelines for building components in a React/Next.js application using Ant Design and consistent design tokens. It ensures all new components match the existing design system with proper colors, spacing, typography, and interaction patterns.
## When to Use This Skill
Trigger this skill when:
- **Creating UI components**: forms, tables, modals, cards, lists
- **Adding new features** that require UI elements
- **Implementing loading states** or animations
- **Styling components** to match the design system
- **User asks to build/create/add** any visual component
## Out of Scope — Stop and Do Something Else
If the work you are about to do is any of the following, **stop using this skill** and take the redirect instead. Nothing below applies:
- **Charts, graphs, plots, or data-visualization palettes** (categorical / sequential / diverging series colors, sparklines, heatmaps, stat tiles, dashboard chart layout). This skill carries **no** chart guidance, and its brand palette is not a series palette — do not extrapolate one from it. Use a dedicated data-visualization skill or reference (`dataviz`, where available) instead.
- **A codebase that is not standardized on Ant Design** — Tailwind-only, Material UI, Chakra, or plain CSS. None of the patterns below transfer; follow that stack's own conventions.
- **A general accessibility or UX audit.** This is one application's house style, not an a11y reference.
Charts are out of scope regardless of what a reference file says — see the note on `styling-layout.md` under [Reference Files](#reference-files).
## Quick Start
### Step 1: Identify Component Type
Determine what you're building:
- **Drawer/Side Panel** → Read `references/component-patterns.md` (Drawer Patterns section) **[MANDATORY PATTERN]**
- **Data Table** → Read `references/codebase-patterns.md` (Tables section)
- **Form/Modal** → Read `references/codebase-patterns.md` (Modal Patterns section)
- **Card/Grid** → Read `references/codebase-patterns.md` (Card Patterns section)
- **Need colors/spacing** → Read `references/design-tokens.md`
- **Need animations/loading** → Read `references/animations.md`
### Step 2: Follow the Component Checklist
This is the **authoritative** checklist — use it both before you start and before you call the component done. Two reference files carry narrower, topic-scoped checklists (`styling-layout.md` for layout, `animations.md` for animation). They supplement this one; where either disagrees with this list, **this list wins**.
Every component must:
- [ ] Use Ant Design components as the base
- [ ] Apply consistent spacing (8px, 12px, 16px, 24px)
- [ ] Use theme tokens (`token.colorText`, `token.colorBgContainer`)
- [ ] Use `fontSize: 12` for tables (MANDATORY — see `references/component-patterns.md`)
- [ ] Include proper TypeScript types
- [ ] Handle loading states (Skeleton, Spin, or loading prop)
- [ ] Show feedback via `App.useApp()` — never the static `message` / `notification` / `Modal` imports (see [Feedback APIs](#feedback-apis))
- [ ] Include validation rules with clear messages on every form input
- [ ] Include proper error handling
- [ ] Support responsive design
- [ ] Match the existing patterns below
### Step 3: Apply Core Design Tokens
**Colors** (canonical source: `references/design-tokens.md` — if these ever disagree, that file wins):
- Brand Orange: `#F79400` (primary brand color)
- Product Owner: `#7C4DFF` (purple)
- Tech Owner: `#52c41a` (green)
- Error/Overdue: `#ff4d4f` (red)
- Always use `theme.useToken()` for dynamic colors
**Spacing:**
- Small gap: `8px`
- Medium gap: `12px`
- Standard padding: `16px`
- Section margin: `24px`
**Typography:**
- Table cells: `fontSize: 12`
- Secondary text: `fontSize: '11px'`
- Strong text: `<Text strong>`
- Secondary: `<Text type="secondary">`
## Feedback APIs
**MANDATORY: get `message`, `notification` and `modal` from `App.useApp()`. Never call the static `message.*` / `notification.*` / `Modal.confirm()` imports.**
This is not a style preference — it is forced by the `ConfigProvider` theming that the rest of this skill mandates. Ant Design's own docs state it plainly:
> Static methods like message, notification, and Modal.confirm do not inherit context from `ConfigProvider` because they are rendered to independent DOM nodes. To resolve style issues, use hooks like `message.useMessage`, `notification.useNotification`, `Modal.useModal`, or the `App.useApp` hook.
> — [antd FAQ](https://ant.design/docs/react/faq)
> we recommend to use top level registration instead of `notification` static method, because static method cannot consume context, and ConfigProvider data will not work.
> — [antd notification docs](https://ant.design/components/notification)
Measured on antd 5.29.3: inside `<ConfigProvider prefixCls="zzz" theme={{ token: { colorPrimary: '#F79400' } }}>`, a static `message.success()` rendered its holder with the **`ant-`** prefix and the **default** theme hash, while `App.useApp().message.success()` rendered it with the configured **`zzz-`** prefix and a *different*, configured hash. The static call silently ignored both the prefix and the brand token. (Reproduce it by diffing the two holders' class names — the exact hash strings are build-specific, so compare them against each other rather than against any literal quoted here.)
### Setup (once, at the app root)
`App` must sit **inside** `ConfigProvider` so it inherits the theme:
```tsx
import { ConfigProvider, App } from "antd";
export default function Providers({ children }) {
return (
<ConfigProvider theme={{ token: { colorPrimary: "#F79400" } }}>
<App>{children}</App>
</ConfigProvider>
);
}
```
### Usage (every component)
```tsx
import { App, Button } from "antd";
export default function MyComponent() {
// Call the hook at the top of the component...
const { message, notification, modal } = App.useApp();
// ...but FIRE the feedback from an event handler or an effect, never during render.
// antd warns ("You are calling notice in render") and the notice is dropped.
const handleSave = async () => {
try {
await save();
message.success("Saved");
} catch (err) {
notification.error({ message: "Save failed", description: String(err) });
}
};
const handleDelete = () => {
modal.confirm({ title: "Are you sure?", onOk: doDelete });
};
return (
<>
<Button onClick={handleSave}>Save</Button>
<Button danger onClick={handleDelete}>Delete</Button>
</>
);
}
```
| Don't (static — ignores `ConfigProvider`) | Do (`App.useApp()`) |
|---|---|
| `import { message } from "antd"; message.success(...)` | `const { message } = App.useApp(); message.success(...)` |
| `import { notification } from "antd"; notification.error(...)` | `const { notification } = App.useApp(); notification.error(...)` |
| `Modal.confirm({...})` | `const { modal } = App.useApp(); modal.confirm({...})` |
`App.useApp()` is a hook — call it at the top of the component, not inside a callback. For feedback fired outside React (an axios interceptor, a plain util), lift the call into a component or pass the instance in; do not fall back to the static import.
**Note:** `<Modal>` used as a *component* (Pattern 2 below) is unaffected — it renders inside the tree and inherits context normally. Only the static `Modal.confirm()` / `Modal.info()` family is affected.
## Core Patterns
### Pattern 1: Data Tables
All data tables should follow this structure:
```tsx
import { Table, Input, Select, ConfigProvider, theme } from "antd";
import { SearchOutlined } from "@ant-design/icons";
export default function DataTable() {
const { token } = theme.useToken();
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
{/* Filters row */}
<div style={{ marginBottom: 16, display: "flex", gap: "8px" }}>
<Input placeholder="Search..." prefix={<SearchOutlined />} style={{ flex: 1 }} allowClear />
<Select style={{ flex: 1 }} placeholder="Filter" allowClear />
</div>
{/* Table with custom theme */}
<ConfigProvider theme={{
components: { Table: { headerBg: token.colorBgContainer, fontSize: 12 } }
}}>
<Table
dataSource={data}
loading={isLoading}
rowKey="id"
size="small"
pagination={false}
scroll={{ y: 'calc(100vh - 220px)', x: 'max-content' }}
/>
</ConfigProvider>
</div>
);
}
```
**Key details:**
- Use `ConfigProvider` for table theme customization
- Set `fontSize: 12` for compact display
- Use `scroll={{ y: 'calc(100vh - 220px)' }}` for proper scrolling
- Always include `rowKey="id"`
- Set `size="small"` for compact tables
### Pattern 2: Forms in Modals
Standard form modal pattern:
```tsx
import { Modal, Form, Input, Button, App } from "antd";
export default function AddModal({ isOpen, onClose, onSuccess }) {
// MANDATORY: not the static `message` import — it ignores ConfigProvider.
// See "Feedback APIs" above.
const { message } = App.useApp();
const [form] = Form.useForm();
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setIsSubmitting(true);
await api.post('/endpoint', values);
message.success("Created successfully");
form.resetFields();
onSuccess();
onClose();
} catch (error) {
message.error(error.response?.data?.error || "Failed to create");
} finally {
setIsSubmitting(false);
}
};
return (
<Modal title="Add Item" open={isOpen} onCancel={onClose} footer={null} maskClosable={true}>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item name="name" label="Name" rules={[{ required: true, message: "Please enter name" }]}>
<Input placeholder="Enter name" />
</Form.Item>
<Form.Item style={{ marginBottom: 0, marginTop: 16, textAlign: "right" }}>
<Button onClick={onClose} style={{ marginRight: 8 }}>Cancel</Button>
<Button htmlType="submit" loading={isSubmitting}>Create</Button>
</Form.Item>
</Form>
</Modal>
);
}
```
**Key details:**
- Use `layout="vertical"` for labels above inputs
- Include validation rules with clear messages
- Reset form on success: `form.resetFields()`
- Show feedback via `const { message } = App.useApp()` — the static `message` import ignores `ConfigProvider` ([Feedback APIs](#feedback-apis))
- Set `maskClosable={true}` for better UX
### Pattern 3: Selectable Card Grids
Horizontal scrolling cards with selection:
```tsx
import { theme, Typography, Avatar } from "antd";
const { Text } = Typography;
const { token } = theme.useToken();
<div style={{
display: "flex",
gap: "12px",
overflowX: "auto",
paddingBottom: "4px"
}}>
{items.map((item) => {
const isSelected = selectedId === item.id;
return (
<div
key={item.id}
onClick={() => setSelectedId(isSelected ? null : item.id)}
style={{
flex: 1,
minWidth: '200px',
maxWidth: '280px',
padding: '12px',
cursor: 'pointer',
borderRadius: '8px',
border: isSelected ? '1px solid #F79400' : `1px solid ${token.colorBorder}`,
backgroundColor: isSelected ? token.colorFillSecondary : token.colorBgContainer,
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.04)',
}}
>
<Text strong style={{ fontSize: '14px' }}>{item.name}</Text>
{/* Additional content */}
</div>
);
})}
</div>
```
**Key details:**
- Selected state: border with brand primary color
- Subtle shadow: `0 1px 2px rgba(0, 0, 0, 0.04)`
- Border radius: `8px`
- Use `token.colorBorder` for unselected state
### Pattern 4: Loading States
Always show loading feedback:
```tsx
// Table loading
<Table loading={isLoading} dataSource={data} />
// Card loading skeleton
{data === undefined ? (
<Card loading style={{ minWidth: '200px' }} />
) : (
<Card>{content}</Card>
)}
// Button loading
<Button htmlType="submit" loading={isSubmitting}>Submit</Button>
// Page content skeleton
<Skeleton active paragraph={{ rows: 4 }} />
```
### Pattern 5: Avatars with Fallbacks
```tsx
{user.profilePic ? (
<Avatar size={24} src={getCachedAvatarUrl(user.profilePic)} />
) : (
<Avatar size={24} style={{ backgroundColor: getAvatarColor(user.name) }}>
{user.name.charAt(0).toUpperCase()}
</Avatar>
)}
```
## Styling Approach
### Priority Order
1. **Ant Design props** first (type, size, danger, etc.)
2. **Theme tokens** for colors (`token.colorBgContainer`)
3. **Inline styles** for layout and spacing
4. **Tailwind** rarely (only for utility classes)
### DO's ✅
- Use Ant Design components as base
- Use `theme.useToken()` for colors
- Apply consistent spacing (8px, 12px, 16px, 24px)
- Include loading states everywhere
- Show user feedback with messages
- Handle errors gracefully
- Use TypeScript types
### DON'Ts ❌
- Don't use CSS-in-JS libraries
- Don't create custom CSS files
- Don't hardcode a color that has a theme token (`token.colorText`, `token.colorBorder`, `token.colorBgContainer`) — the brand palette in Step 3 is the documented exception and is written literally, as the patterns above show
- Don't skip error handling
- Don't ignore responsive design
- Don't use excessive shadows
## Common Recipes
### Status Tag
```tsx
<Tag color={status.color || "#d9d9d9"} style={{ borderRadius: "8px", fontSize: 12 }}>
{status.name || "Not Set"}
</Tag>
```
### Clickable Text
```tsx
<Text strong style={{ cursor: 'pointer', fontSize: 12 }} onClick={() => router.push(`/path/${id}`)}>
{title}
</Text>
```
### Overdue Indicator
```tsx
{isOverdue && (
<Tooltip title={`Overdue since ${date}`}>
<div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#ff4d4f' }} />
</Tooltip>
)}
```
### Select with Item Counts
```tsx
<Select>
{items.map(item => (
<Option key={item.id} value={item.id}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span>{item.name}</span>
<Text type="secondary" style={{ fontSize: '11px' }}>{item.count} items</Text>
</div>
</Option>
))}
</Select>
```
## Reference Files
Read these files for detailed information:
1. **[design-tokens.md](references/design-tokens.md)** - Colors, spacing, typography system. **Canonical for every color value.**
2. **[codebase-patterns.md](references/codebase-patterns.md)** - Real patterns from existing code
3. **[component-patterns.md](references/component-patterns.md)** - Ant Design component standards
4. **[styling-layout.md](references/styling-layout.md)** - Layout patterns and responsive design. Written Tailwind-first, so it reads against the grain of this file's Ant-Design-first mandates; its known conflicts (spacing grid, CSS files, inline styles, z-index, breakpoints, router, brand primary, charts) are reconciled inline in that file. Where anything there still disagrees with this file, **this file wins**.
5. **[animations.md](references/animations.md)** - Loading indicators and transitions. Drawer/modal behaviour is owned by `component-patterns.md`; that file wins on any drawer conflict.
## Typography Scale
```tsx
// Strong text (table headers, card titles)
<Text strong style={{ fontSize: '12px' }}>Title</Text>
// Regular text (table cells, body)
<Text style={{ fontSize: '12px' }}>Content</Text>
// Secondary text (subtitles, metadata)
<Text type="secondary" style={{ fontSize: '11px' }}>Metadata</Text>
// Tertiary text (additional info)
<Text style={{ fontSize: '11px', color: token.colorTextTertiary }}>Info</Text>
```
## Page Layout
Standard full-height page layout:
```tsx
export default function Page() {
return (
<div style={{
height: "100%",
display: "flex",
flexDirection: "column",
overflow: "hidden",
padding: "24px 40px 24px 24px"
}}>
{/* Page content with proper scrolling */}
</div>
);
}
```
## Data Fetching
Use SWR for data fetching:
```tsx
import useSWR from "swr";
import { fetcher } from "@/lib/axios";
const { data, error, isLoading, mutate } = useSWR(
'/api/endpoint',
fetcher,
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
}
);
```
## Before You Finish
Re-run the checklist in [Step 2](#step-2-follow-the-component-checklist) — there is no separate finishing list to diverge from it. If you also worked from `styling-layout.md` or `animations.md`, their topic checklists are supplements to Step 2, never replacements, and Step 2 wins on any conflict.
Files in this skill
- SKILL.md
- references/animations.md
- references/codebase-patterns.md
- references/component-patterns.md
- references/design-tokens.md
- references/styling-layout.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.