关于 chakra-ui-refactor
面向使用 Chakra UI v3 的开发者,帮助审查和重构界面代码,也可将其他样式方案转换为 Chakra。流程会结合代码意图与项目环境,检查无障碍、响应式、API 用法和可维护性。
主要功能
- 01根据需求区分审查与重构
- 02检查无障碍和响应式表现
- 03核对 Chakra UI v3 API 用法
- 04将 HTML、CSS、Tailwind 等转换为 Chakra
- 05保留现有行为并指出改进项
适用场景
- 01审查 Chakra UI 组件并定位问题
- 02将 Tailwind 界面迁移为 Chakra
- 03清理旧版 Chakra API 与样式写法
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ chakra-ui/ chakra-ui --skill chakra-ui-refactor安装后在 Claude Code 中输入/chakra-ui-refactor确认已加载。
详细介绍
Chakra UI 重构与审查
你正在使用 Chakra UI v3 审查和改进 UI 代码。根据开发者的需求,你要产出结构化的评审意见、重写后的代码,或两者兼有。在产出任何内容之前,先完整阅读代码和项目上下文。
第 1 步 — 定位并确定意图
在产出任何内容之前,先确定:
- Chakra UI 版本 — 检查
package.json;默认使用 v3 - 框架 — Next.js App Router、Pages Router、Vite、纯 React
- 源码类型 — 现有 Chakra、纯 HTML/CSS、Tailwind、CSS Modules、 styled-components
- 用户的诉求:
- 仅审查 — "check this"、"is this correct/idiomatic"、"what's wrong"、 "review my code" → 产出评审意见及针对性修复,不做完整重写
- 重构 / 转换 — "refactor this"、"convert from Tailwind"、"clean this up" → 产出重写后的代码
- 两者都要 — "review and fix" → 先评审,再给出重写后的代码
在回复开头说明你的判断(例如 "Reviewing as existing Chakra v3 code. Assuming Next.js App Router.")。
如果尚未分享代码,请索取代码。不要审查对代码的描述。
第 2 步 — 分析代码
无论输出模式如何,都按以下维度通读代码。对于审查,这些维度会成为发现的问题。对于重构,它们会成为需要修复的检查清单。
无障碍性
- 所有交互元素都有无障碍标签吗?(图标按钮上的
aria-label、label+input 组合上的htmlFor/id、图片上的alt) - 键盘导航是否可行?(焦点环未被抑制,交互元素确实可聚焦)
- 标题层级是否合理?(没有跳级,没有把
h1当作样式捷径使用) - 表单字段是否用
Field.Root包裹,并配有Field.Label和Field.ErrorText? - 组件在不以颜色作为唯一信号时是否仍能正常工作?
响应式
- 布局组件是否在多个断点指定了行为?
- 是否存在本可使用响应式 token 却硬编码像素值的地方?
- 这在移动端会出问题吗?(固定宽度、小视口上的
overflow: hidden)
Chakra API 正确性
- 是否使用了 v3 的 prop 名称?(用
disabled而非isDisabled,用colorPalette而非colorScheme,用gap而非spacing,用open而非isOpen) - 复合组件是否使用正确?(
Field.Root/Field.Label、Dialog.Root/Dialog.Content等) - 在 Next.js App Router 中
"use client"的位置是否正确? - 是否仍存在 v2 模式?(
extendTheme、ColorModeScript、useColorModeValue、sxprop)
Token 与样式使用
- 是否存在本可使用语义 token 却硬编码颜色的地方?(
bg="#f9fafb"→bg="bg.subtle") - 是否使用了原始十六进制值或调色板值而非语义 token?这些不会遵循深色模式。
- 是否存在本应作为 Chakra 样式 prop 的内联
style={{}}prop?
组件结构
- 是否存在不必要的嵌套?(一个
Box就够时却写成Box > Box > Box) - 是否在本可使用
Stack gap={4}更简洁的地方使用手动间距(在每个子元素上加mt={4})? - 是否使用了正确的布局原语?(
Flex与Stack与Grid与SimpleGrid)
可维护性
- 同一视觉模式是否重复出现 3 次以上?(可作为组件或 recipe 的候选)
- 是否存在暗示 recipe 或 slot recipe 的一次性样式覆盖?
- prop 类型 / TypeScript 类型是否存在且准确?
步骤 3a — 审查输出
当用户想要的是点评而非重写时,使用本节。
按影响程度对发现的问题分类:
严重 — 会破坏行为或排除用户的 bug 与无障碍缺陷
- 仅含图标的按钮缺少
aria-label - 表单字段没有关联的 label
- 带
onClick但无法键盘访问的交互式Box - 错误的 v3 prop 名称会静默失效(
isDisabled在 v3 中不会禁用) - 在 App Router 中使用 hooks 的组件缺少
"use client"
改进项 — 不紧急的正确性与质量问题
- 硬编码颜色,会破坏深色模式
- 缺少响应式断点
- 不必要的嵌套或错误的布局原语
- 仍能工作但应更新的 v2 模式
可选建议 — 非阻塞性的想法
- 将重复的模式提取为组件
- 用 recipe 变体替换一次性样式
- 补充缺失的 TypeScript 类型
对每个严重问题和重要改进,展示一个最小修复:
**Missing aria-label on close button** (Critical)
The IconButton for closing the dialog has no accessible label.
// Before
<IconButton icon={<CloseIcon />} onClick={onClose} />
// After
<IconButton aria-label="Close dialog" icon={<CloseIcon />} onClick={onClose} />
没有可报告内容的章节就跳过。篇幅要与代码相称 —— 一个 20 行的组件需要的是紧凑的审查,而不是面面俱到的长篇。
步骤 3b — 重构 / 转换输出
当用户想要的是重写后的代码时,使用本节。
按来源划分的转换策略
来自纯 HTML / CSS
| HTML | Chakra 等价写法 |
|---|---|
<div> 布局容器 | Box、Flex、Stack、Grid |
<section>、<article> | Box as="section"、Box as="article" |
<nav> | Box as="nav" |
<ul> / <li> | Box as="ul" / Box as="li",或 Stack |
<button> | Button 或 IconButton |
<a> | Link |
<img> | Image(保留 alt) |
<input>、<select> | Field.Root 内的 Input、NativeSelect |
| CSS | Chakra 样式 prop |
|---|---|
display: flex | Flex 或 display="flex" |
flex-direction: column | Stack 或 flexDir="column" |
gap: 16px | gap={4}(1 单位 = 4px) |
padding: 16px 24px | py={4} px={6} |
border-radius: 8px | rounded="md" |
color: #6b7280 | color="fg.muted" |
background: #f9fafb | bg="bg.subtle" |
来自 Tailwind CSS
| Tailwind | Chakra |
|---|---|
flex、flex-col、flex-row | Flex、flexDir |
gap-4 | gap={4} |
p-4、px-6、py-2 | p={4}、px={6}、py={2} |
text-sm、font-bold | fontSize="sm"、fontWeight="bold" |
rounded-lg、shadow-md | rounded="lg"、shadow="md" |
w-full、max-w-lg | w="full"、maxW="lg" |
hidden md:flex | display={{ base: "none", md: "flex" }} |
grid grid-cols-3 | SimpleGrid columns={3} |
text-gray-500、bg-gray-100 | color="fg.muted"、bg="bg.subtle" |
hover:bg-gray-100 | _hover={{ bg: "bg.subtle" }} |
将 Tailwind 的响应式前缀替换为 Chakra 的断点对象语法:
// Tailwind: text-sm md:base lg:text-lg
<Text fontSize={{ base: "sm", md: "md", lg: "lg" }} />
来自 CSS Modules —— 尽可能转换为 Chakra props;对于无法用 props 表达的样式(动画、复杂选择器),保留 className:
// Before
<div className={styles.card}>...</div>
// After — converted to props; className kept only for unconvertible styles
<Box p={4} rounded="lg" shadow="sm" className={styles.fadeIn}>...</Box>
当所有类名都消除后,完全移除该 import。
来自 styled-components / @emotion/styled —— 映射为带有等价样式 props 的 Box,然后移除 import,若其他地方不再使用则卸载:
// Before
const Card = styled.div`padding: 1rem; &:hover { background: #f3f4f6; }`
// After
<Box p={4} _hover={{ bg: "bg.muted" }} />
来自现有 Chakra UI(清理)
- 展平
Box > Box > Box嵌套;将每个子元素上的mt/mb替换为Stack gap={N} - 将
sx替换为css(v3 重命名);更新其内部的嵌套&:hover选择器 - 将
bg="gray.50"替换为bg="bg.subtle"以及其他语义 token 的等价写法 - 更新 v2 prop 名称:
isDisabled→disabled、colorScheme→colorPalette、spacing→gap - 更新复合组件:
FormControl→Field.Root、Modal→Dialog、Select→NativeSelect
保持行为 —— 不可妥协
- 保持所有事件处理器、状态变量和条件渲染完全不变
- 保留
aria-*属性;在明显需要的地方补充缺失的属性 - 保持语义化 HTML 意图(
<nav>→Box as="nav",而不仅仅是Box) - 在存在
"use client"的地方保留它;仅当组件确实需要时才添加 - 不要仅因为组件使用了 Chakra UI 就添加
"use client" - 一个能正常工作的部分转换组件,胜过一个无法正常工作的完全转换组件
用于 Next.js Link 和 Image 的 asChild
import NextLink from "next/link"
<ChakraLink asChild><NextLink href="/about">About</NextLink></ChakraLink>
import NextImage from "next/image"
<ChakraImage asChild><NextImage src="/hero.png" alt="Hero" width={800} height={400} /></ChakraImage>
重构输出格式
1. 重构后的代码 — 完整、可运行、导入正确
2. 变更内容 — 简明列表,聚焦于不明显的决策:
- Replaced <div className="flex gap-4"> with <Flex gap={4}>
- Replaced bg="#f9fafb" with bg="bg.subtle" for dark mode compatibility
- Kept form submit handler and validation logic unchanged
- Added aria-label to close icon button (was missing)
3. 建议(可选)— 超越本次重构的有意义的改进: 提取可复用组件、采用 recipe、迁移到 v2 模式。
何时询问 vs 直接继续
如果代码和意图清晰,就直接继续。以下情况需要询问:
- 代码尚未共享
- 组件非常庞大且范围不明确
- 存在你看不到的上下文或状态,且会影响评审
- 存在可被多种方式解读的模糊行为
当你未询问就继续时,请在回复开头说明假设。