chakra-ui-refactor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Chakra UI Refactor & Review

Chakra UI 重构与审查

You are reviewing and improving UI code using Chakra UI v3. Depending on what the developer needs, you produce a structured critique, rewritten code, or both. Read the code and project context fully before producing any output.

你将使用Chakra UI v3来审查和优化UI代码。根据开发者的需求,你需要输出结构化的评审意见、重写后的代码,或者两者兼具。在输出任何内容前,请完整阅读代码及项目上下文。

Step 1 — Orient and determine intent

步骤1 — 明确方向与需求

Before any output, establish:
  • Chakra UI version — check
    package.json
    ; use v3 by default
  • Framework — Next.js App Router, Pages Router, Vite, plain React
  • Source type — existing Chakra, plain HTML/CSS, Tailwind, CSS Modules, styled-components
  • What the user is asking:
    • Review only — "check this", "is this correct/idiomatic", "what's wrong", "review my code" → produce a critique with targeted fixes, no full rewrite
    • Refactor / convert — "refactor this", "convert from Tailwind", "clean this up" → produce rewritten code
    • Both — "review and fix" → critique first, then the rewritten code
State your reading at the top of the response (e.g. "Reviewing as existing Chakra v3 code. Assuming Next.js App Router.").
If code isn't shared yet, ask for it. Don't review a description of code.

在输出内容前,先确定以下信息:
  • Chakra UI版本 — 查看
    package.json
    ;默认使用v3版本
  • 框架 — Next.js App Router、Pages Router、Vite、纯React
  • 代码来源类型 — 现有Chakra代码、纯HTML/CSS、Tailwind、CSS Modules、styled-components
  • 用户需求类型
    • 仅审查 — “检查这个”“这样是否规范/正确”“这有什么问题”“帮我评审代码” → 输出带有针对性修复方案的评审意见,无需完整重写代码
    • 重构/转换 — “重构这个”“从Tailwind转换过来”“整理一下这个代码” → 输出重写后的代码
    • 两者兼具 — “审查并修复” → 先输出评审意见,再提供重写后的代码
在响应内容顶部说明你的判断(例如:“正在评审现有Chakra v3代码,假设使用Next.js App Router。”)。
如果用户尚未提供代码,请要求其提供。不要仅根据代码描述进行评审。

Step 2 — Analyze the code

步骤2 — 代码分析

Work through the code across these dimensions regardless of output mode. For review, they become findings. For refactor, they become the checklist of what to fix.
Accessibility
  • Do all interactive elements have accessible labels? (
    aria-label
    on icon buttons,
    htmlFor
    /
    id
    on label+input pairs,
    alt
    on images)
  • Is keyboard navigation possible? (focus rings not suppressed, interactive elements are actually focusable)
  • Does the heading hierarchy make sense? (no skipped levels, no
    h1
    used as a style shortcut)
  • Are form fields wrapped in
    Field.Root
    with
    Field.Label
    and
    Field.ErrorText
    ?
  • Does the component work without color as the only signal?
Responsiveness
  • Do layout components specify behavior at multiple breakpoints?
  • Are there hardcoded pixel values where responsive tokens would work better?
  • Would this break on mobile? (fixed widths,
    overflow: hidden
    on small viewports)
Chakra API correctness
  • Are v3 prop names used? (
    disabled
    not
    isDisabled
    ,
    colorPalette
    not
    colorScheme
    ,
    gap
    not
    spacing
    ,
    open
    not
    isOpen
    )
  • Are compound components used correctly? (
    Field.Root
    /
    Field.Label
    ,
    Dialog.Root
    /
    Dialog.Content
    , etc.)
  • Is
    "use client"
    placed correctly in Next.js App Router?
  • Are there v2 patterns still present? (
    extendTheme
    ,
    ColorModeScript
    ,
    useColorModeValue
    ,
    sx
    prop)
Token and style usage
  • Are hardcoded colors used where semantic tokens would work? (
    bg="#f9fafb"
    bg="bg.subtle"
    )
  • Are raw hex or palette values used instead of semantic tokens? These won't respect dark mode.
  • Are there inline
    style={{}}
    props that should be Chakra style props?
Component structure
  • Is there unnecessary nesting? (
    Box > Box > Box
    when one would do)
  • Is manual spacing (
    mt={4}
    on every child) used where
    Stack gap={4}
    would be cleaner?
  • Are the right layout primitives used? (
    Flex
    vs
    Stack
    vs
    Grid
    vs
    SimpleGrid
    )
Maintainability
  • Does the same visual pattern repeat 3+ times? (candidate for a component or recipe)
  • Are there one-off style overrides that suggest a recipe or slot recipe?
  • Are prop types / TypeScript types present and accurate?

无论输出哪种内容,都需要从以下维度分析代码。对于评审场景,这些维度将作为发现的问题点;对于重构场景,这些维度将作为修复检查清单。

Step 3a — Review output

可访问性

Use this when the user wants a critique, not a rewrite.
Categorize findings by impact:
Critical — bugs and accessibility failures that break behavior or exclude users
  • Missing
    aria-label
    on an icon-only button
  • Form field with no label association
  • Interactive
    Box
    with
    onClick
    but no keyboard access
  • Wrong v3 prop name that silently does nothing (
    isDisabled
    doesn't disable in v3)
  • "use client"
    missing on a component that uses hooks in App Router
Improvements — correctness and quality issues that aren't urgent
  • Hardcoded colors that break dark mode
  • Missing responsive breakpoints
  • Unnecessary nesting or wrong layout primitive
  • v2 patterns that still work but should be updated
Optional suggestions — non-blocking ideas
  • Extract a repeated pattern into a component
  • Replace a one-off style with a recipe variant
  • Add a missing TypeScript type
For each critical issue and significant improvement, show a minimal fix:
**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} />
Skip sections with nothing to report. Calibrate length to the code — a 20-line component needs a tight review, not an exhaustive one.

  • 所有交互元素是否都有可访问标签?(图标按钮上的
    aria-label
    、标签+输入框对的
    htmlFor
    /
    id
    、图片的
    alt
    属性)
  • 是否支持键盘导航?(未隐藏焦点环、交互元素确实可获取焦点)
  • 标题层级是否合理?(没有跳过层级、未将
    h1
    仅用作样式快捷方式)
  • 表单字段是否用
    Field.Root
    包裹,并搭配
    Field.Label
    Field.ErrorText
  • 组件是否不依赖颜色作为唯一的提示信号?

Step 3b — Refactor / convert output

响应式

Use this when the user wants rewritten code.
  • 布局组件是否指定了多断点下的行为?
  • 是否存在硬编码像素值,而使用响应式令牌会更合适?
  • 在移动端是否会出现问题?(固定宽度、小视口下的
    overflow: hidden

Conversion strategy by source

Chakra API正确性

From plain HTML / CSS
HTMLChakra equivalent
<div>
layout wrapper
Box
,
Flex
,
Stack
,
Grid
<section>
,
<article>
Box as="section"
,
Box as="article"
<nav>
Box as="nav"
<ul>
/
<li>
Box as="ul"
/
Box as="li"
, or
Stack
<button>
Button
or
IconButton
<a>
Link
<img>
Image
(preserve
alt
)
<input>
,
<select>
Input
,
NativeSelect
inside
Field.Root
CSSChakra style prop
display: flex
Flex
or
display="flex"
flex-direction: column
Stack
or
flexDir="column"
gap: 16px
gap={4}
(1 unit = 4px)
padding: 16px 24px
py={4} px={6}
border-radius: 8px
rounded="md"
color: #6b7280
color="fg.muted"
background: #f9fafb
bg="bg.subtle"
From Tailwind CSS
TailwindChakra
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" }}
Replace Tailwind responsive prefixes with Chakra's breakpoint object syntax:
tsx
// Tailwind: text-sm md:base lg:text-lg
<Text fontSize={{ base: "sm", md: "md", lg: "lg" }} />
From CSS Modules — convert what you can to Chakra props; keep
className
for styles that can't be expressed as props (animations, complex selectors):
tsx
// 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>
Once all class names are eliminated, remove the import entirely.
From styled-components / @emotion/styled — map to
Box
with equivalent style props, then remove the import and uninstall if no longer used elsewhere:
tsx
// Before
const Card = styled.div`padding: 1rem; &:hover { background: #f3f4f6; }`
// After
<Box p={4} _hover={{ bg: "bg.muted" }} />
From existing Chakra UI (cleanup)
  • Flatten
    Box > Box > Box
    nesting; replace
    mt
    /
    mb
    on every child with
    Stack gap={N}
  • Replace
    sx
    with
    css
    (v3 rename); update nested
    &:hover
    selectors inside it
  • Replace
    bg="gray.50"
    bg="bg.subtle"
    and other semantic token equivalents
  • Update v2 prop names:
    isDisabled→disabled
    ,
    colorScheme→colorPalette
    ,
    spacing→gap
  • Update compound components:
    FormControl→Field.Root
    ,
    Modal→Dialog
    ,
    Select→NativeSelect
  • 是否使用了v3版本的属性名?(
    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
    sx
    属性)

Preserve behavior — non-negotiable

令牌与样式使用

  • Keep all event handlers, state variables, and conditional rendering exactly as-is
  • Keep
    aria-*
    attributes; add missing ones where clearly needed
  • Keep semantic HTML intent (
    <nav>
    Box as="nav"
    , not just
    Box
    )
  • Keep
    "use client"
    where it exists; add it only when the component genuinely needs it
  • Don't add
    "use client"
    just because a component uses Chakra UI
  • A partially-converted component that works is better than a fully-converted one that doesn't
  • 是否在应使用语义令牌的地方使用了硬编码颜色?(
    bg="#f9fafb"
    bg="bg.subtle"
  • 是否使用了原始十六进制或调色板值而非语义令牌?这些值无法适配深色模式。
  • 是否存在应使用Chakra样式属性的内联
    style={{}}
    属性?

asChild
for Next.js Link and Image

组件结构

tsx
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>
  • 是否存在不必要的嵌套?(可以用一个Box实现时却用了
    Box > Box > Box
  • 是否在可使用
    Stack gap={4}
    的场景下,给每个子元素手动添加了间距(如
    mt={4}
    )?
  • 是否使用了正确的布局原语?(
    Flex
    Stack
    Grid
    SimpleGrid
    的选择是否恰当)

Refactor output format

可维护性

1. Refactored code — complete, runnable, with correct imports
2. What changed — concise list focused on non-obvious decisions:
- 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. Suggestions (optional) — meaningful improvements beyond this refactor: extracting a reusable component, adopting a recipe, migrating a v2 pattern.

  • 相同的视觉模式是否重复出现3次以上?(可提取为组件或模板)
  • 是否存在一次性样式覆盖,表明可使用模板或插槽模板?
  • 是否存在Prop类型/TypeScript类型,且类型是否准确?

When to ask vs proceed

步骤3a — 评审输出

Proceed if the code and intent are clear. Ask when:
  • The code isn't shared yet
  • The component is very large and scope is unclear
  • There's context or state you can't see that would change the review
  • There's ambiguous behavior that could be interpreted multiple ways
State assumptions at the top of the response when you proceed without asking.
当用户仅需要评审意见而非重写代码时,使用此输出方式。
按影响程度对发现的问题进行分类:

严重问题 — 破坏功能或导致用户无法正常使用的Bug与可访问性缺陷

  • 纯图标按钮缺少
    aria-label
  • 表单字段未关联标签
  • 带有
    onClick
    的交互式
    Box
    不支持键盘访问
  • 使用了错误的v3属性名,导致功能静默失效(v3中
    isDisabled
    无法禁用组件)
  • 在App Router中,使用钩子的组件缺少
    "use client"

优化建议 — 不紧急的正确性与质量问题

  • 硬编码颜色导致深色模式失效
  • 缺少响应式断点
  • 不必要的嵌套或错误的布局原语
  • 仍在使用v2模式,虽然仍能工作但应更新

可选建议 — 不影响功能的改进思路

  • 将重复模式提取为组件
  • 用模板变体替代一次性样式
  • 添加缺失的TypeScript类型
对于每个严重问题和重要优化建议,提供最小修复示例:
**关闭按钮缺少aria-label**(严重问题)
对话框的关闭图标按钮没有可访问标签。

// 修复前
<IconButton icon={<CloseIcon />} onClick={onClose} />
// 修复后
<IconButton aria-label="Close dialog" icon={<CloseIcon />} onClick={onClose} />
若无相关问题,可跳过对应章节。评审内容长度应与代码规模匹配——20行的组件只需简洁的评审,无需面面俱到。

步骤3b — 重构/转换输出

当用户需要重写代码时,使用此输出方式。

按来源分类的转换策略

从纯HTML/CSS转换

HTMLChakra等价组件/属性
<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>
Input
,
NativeSelect
包裹在
Field.Root
CSS属性Chakra样式属性
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的断点对象语法:
tsx
// Tailwind: text-sm md:base lg:text-lg
<Text fontSize={{ base: "sm", md: "md", lg: "lg" }} />

从CSS Modules转换 — 尽可能将样式转换为Chakra属性;对于无法用属性表达的样式(动画、复杂选择器),保留
className

tsx
// 转换前
<div className={styles.card}>...</div>
// 转换后 — 可转换部分改为属性;仅保留无法转换的样式的className
<Box p={4} rounded="lg" shadow="sm" className={styles.fadeIn}>...</Box>
当所有类名都已消除后,完全移除对应的导入语句。

从styled-components / @emotion/styled转换 — 映射为带有等价样式属性的
Box
,然后移除导入语句,若其他地方不再使用则可卸载相关依赖:

tsx
// 转换前
const Card = styled.div`padding: 1rem; &:hover { background: #f3f4f6; }`
// 转换后
<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"
    等语义令牌等价写法
  • 更新v2属性名:
    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
用法

tsx
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. 变更说明 — 简洁列出非显而易见的决策:
- 将<div className="flex gap-4">替换为<Flex gap={4}>
- 将bg="#f9fafb"替换为bg="bg.subtle",以适配深色模式
- 保留表单提交处理程序和验证逻辑不变
- 为关闭图标按钮添加了缺失的aria-label
3. 额外建议(可选) — 超出本次重构范围的有意义改进:提取可复用组件、采用模板、迁移v2模式等。

何时询问用户,何时直接处理

若代码和需求清晰,则直接处理。在以下情况时需询问用户:
  • 用户尚未提供代码
  • 组件规模很大且范围不明确
  • 存在你无法看到的上下文或状态,会影响评审结果
  • 存在可被多种方式解读的模糊行为
当你未询问用户而直接处理时,请在响应内容顶部说明你的假设。