pfangueiro/claude-code-agents · Archived

ui-guidelines

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 U…

First seen Mar 1, 2026

Installation

$ npx skills add pfangueiro/claude-code-agents --skill ui-guidelines

Summary

  • 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.

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from pfangueiro/claude-code-agents · top by installs.

npx skills add pfangueiro/claude-code-agents

Browse all from pfangueiro/claude-code-agents

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Also listed on

Alternate registries and mirrors of this skill.

Repository health

Stars 6
License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 17,632 B
  • docs SUMMARY.md 757 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 5 installs

SKILL.md

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

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

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:

import { ConfigProvider, App } from "antd";

export default function Providers({ children }) {
  return (
    <ConfigProvider theme={{ token: { colorPrimary: "#F79400" } }}>
      <App>{children}</App>
    </ConfigProvider>
  );
}

Usage (every component)

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:

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:

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:

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:

// 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

{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

<Tag color={status.color || "#d9d9d9"} style={{ borderRadius: "8px", fontSize: 12 }}>
  {status.name || "Not Set"}
</Tag>

Clickable Text

<Text strong style={{ cursor: 'pointer', fontSize: 12 }} onClick={() => router.push(`/path/${id}`)}>
  {title}
</Text>

Overdue Indicator

{isOverdue && (
  <Tooltip title={`Overdue since ${date}`}>
    <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#ff4d4f' }} />
  </Tooltip>
)}

Select with Item Counts

<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

// 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:

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:

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.