迁移到 v3
如何从 Chakra UI v2.x 迁移到 v3.x
步骤
所需的最低 Node 版本为 Node.20.x
更新包
移除未使用的包@emotion/styled 和 framer-motion。Chakra UI 中不再需要这些包。
npm uninstall @emotion/styled framer-motion安装更新版本的包:@chakra-ui/react 和 @emotion/react。
npm install @chakra-ui/react@latest @emotion/react@latest接下来,使用 CLI 代码片段安装组件代码片段。代码片段提供了预构建的 Chakra 组件组合,以节省您的时间并让您掌控一切。
npx @chakra-ui/cli snippet add重构自定义主题
将您的自定义主题移至专门的 theme.js 或 theme.ts 文件。使用 createSystem 和 defaultConfig 配置您的主题。
之前
import { extendTheme } from "@chakra-ui/react"
export const theme = extendTheme({
fonts: {
heading: `'Figtree', sans-serif`,
body: `'Figtree', sans-serif`,
},
})之后
import { createSystem, defaultConfig } from "@chakra-ui/react"
export const system = createSystem(defaultConfig, {
theme: {
tokens: {
fonts: {
heading: { value: `'Figtree', sans-serif` },
body: { value: `'Figtree', sans-serif` },
},
},
},
})所有令牌值都需要用一个带有 value 键的对象包裹。在此处了解有关令牌的更多信息。
更新 ChakraProvider
将 ChakraProvider 的导入从 @chakra-ui/react 更新为从代码片段导入。接下来,将 theme 属性重命名为 value,以匹配新的基于系统的主题方法。
之前
import { ChakraProvider } from "@chakra-ui/react"
export const App = ({ Component }) => (
<ChakraProvider theme={theme}>
<Component />
</ChakraProvider>
)之后
import { Provider } from "@/components/ui/provider"
import { defaultSystem } from "@chakra-ui/react"
export const App = ({ Component }) => (
<Provider>
<Component />
</Provider>
)import { ColorModeProvider } from "@/components/ui/color-mode"
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
export function Provider(props) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} />
</ChakraProvider>
)
}如果您有自定义主题,请用自定义 system 替换 defaultSystem
Provider 组件由 Chakra 的 ChakraProvider 和 next-themes 的 ThemeProvider 组成
改进
-
性能: 协调性能提升
4 倍,重新渲染性能提升1.6 倍 -
命名空间导入: 使用点表示法导入组件,实现更简洁的导入
import { Accordion } from "@chakra-ui/react" const Demo = () => { return ( <Accordion.Root> <Accordion.Item> <Accordion.ItemTrigger /> <Accordion.ItemContent /> </Accordion.Item> </Accordion.Root> ) } -
TypeScript: 改进了样式属性和令牌的 IntelliSense 和类型推断。
-
多态性: 放宽了
as属性的类型,转而使用asChild属性。此模式受 Radix Primitives 和 Ark UI 启发。
移除的功能
颜色模式
ColorModeProvider和useColorMode已被移除,取而代之的是next-themesLightMode、DarkMode和ColorModeScript组件已被移除。您现在必须使用className="light"或className="dark"来强制主题。useColorModeValue已被移除,取而代之的是next-themes中的useTheme
next-themes 快速设置颜色模式钩子
我们移除了 hooks 包,转而使用专门、健壮的库,如 react-use 和 usehooks-ts
我们现在只提供 useBreakpointValue、useCallbackRef、useDisclosure、useControllableState 和 useMediaQuery 等钩子。
样式配置
我们移除了 styleConfig 和 multiStyleConfig 概念,转而使用 recipes 和 slot recipes。此模式受 Panda CSS 启发。
Next.js 包
我们移除了 @chakra-ui/next-js 包,转而使用 asChild 属性以获得更好的灵活性。
要为 Next.js 图像组件设置样式,请在 Box 组件上使用 asChild 属性。
<Box asChild>
<NextImage />
</Box>
要为 Next.js 链接组件设置样式,请在 Link 组件上使用 asChild 属性
<Link isExternal asChild>
<NextLink />
</Link>
主题工具
我们移除了此包,转而使用 CSS color mix。
之前
我们以前使用 JS 来解析颜色,然后应用透明度
defineStyle({
bg: transparentize("blue.200", 0.16)(theme),
// -> rgba(0, 0, 255, 0.16)
})
之后
我们现在使用 CSS color-mix
defineStyle({
bg: "blue.200/16",
// -> color-mix(in srgb, var(--chakra-colors-200), transparent 16%)
})
forwardRef
由于 as 属性的简化,我们不再提供自定义的 forwardRef。请直接使用 React 的 forwardRef。
之前
import { Button as ChakraButton, forwardRef } from "@chakra-ui/react"
const Button = forwardRef<ButtonProps, "button">(function Button(props, ref) {
return <ChakraButton ref={ref} {...props} />
})
之后
import { Button as ChakraButton } from "@chakra-ui/react"
import { forwardRef } from "react"
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
function Button(props, ref) {
return <ChakraButton ref={ref} {...props} />
},
)
图标
移除了 @chakra-ui/icons 包。建议改用 lucide-react 或 react-icons。
Storybook 插件
我们移除了 Storybook 插件,转而使用 @storybook/addon-themes 和 withThemeByClassName 辅助函数。
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
import { withThemeByClassName } from "@storybook/addon-themes"
import type { Preview, ReactRenderer } from "@storybook/react"
const preview: Preview = {
decorators: [
withThemeByClassName<ReactRenderer>({
defaultTheme: "light",
themes: {
light: "",
dark: "dark",
},
}),
(Story) => (
<ChakraProvider value={defaultSystem}>
<Story />
</ChakraProvider>
),
],
}
export default preview
移除的组件
- StackItem: 您不再需要此组件。请改用
Box。 - FocusLock: 我们不再提供焦点锁定组件。请直接安装并使用
react-focus-lock。 - FormControl: 替换为
Field组件。 - FormErrorMessage: 替换为
Field.ErrorText组件。
之前
<FormControl>
<Input />
<FormErrorMessage>This field is required</FormErrorMessage>
</FormControl>
之后
<Field.Root>
<Input />
<Field.ErrorText>This field is required</Field.ErrorText>
</Field.Root>
-
AlertDialog
- 替换为
Dialog组件并设置role=alertdialog - 将
leastDestructiveRef属性设置为Dialog.Root组件的initialFocusEl
- 替换为
-
Collapse: 替换为
Collapsible组件。
之前
<Collapse in={isOpen} animateOpacity>
Some content
</Collapse>
之后
<Collapsible.Root open={isOpen}>
<Collapsible.Content>Some content</Collapsible.Content>
</Collapsible.Root>
属性更改
布尔属性
将布尔属性的命名约定从 is<X> 更改为 <x>
isOpen->opendefaultIsOpen->defaultOpenisDisabled->disabledisInvalid->invalidisRequired->required
ColorScheme 属性
colorScheme 属性已更改为 colorPalette
之前
- 您只能在组件的主题中使用
colorScheme colorScheme与 HTML 元素中的原生colorScheme属性冲突
<Button colorScheme="blue">Click me</Button>
之后
- 您现在可以在任何地方使用
colorPalette
<Button colorPalette="blue">Click me</Button>
在任何组件中使用,您可以这样做
<Box colorPalette="red">
<Box bg="colorPalette.400">Some box</Box>
<Text color="colorPalette.600">Some text</Text>
</Box>
如果您使用自定义颜色,必须定义两件事才能使 colorPalette 工作
- tokens: 用于 50-950 颜色调色板
- semanticTokens: 用于
solid、contrast、fg、muted、subtle、emphasized和focusRing颜色键
theme.ts
import { createSystem, defaultConfig } from "@chakra-ui/react"
export const system = createSystem(defaultConfig, {
theme: {
tokens: {
colors: {
brand: {
50: { value: "#e6f2ff" },
100: { value: "#e6f2ff" },
200: { value: "#bfdeff" },
300: { value: "#99caff" },
// ...
950: { value: "#001a33" },
},
},
},
semanticTokens: {
colors: {
brand: {
solid: { value: "{colors.brand.500}" },
contrast: { value: "{colors.brand.100}" },
fg: { value: "{colors.brand.700}" },
muted: { value: "{colors.brand.100}" },
subtle: { value: "{colors.brand.200}" },
emphasized: { value: "{colors.brand.300}" },
focusRing: { value: "{colors.brand.500}" },
},
},
},
},
})在此处阅读更多相关信息。
渐变属性
渐变样式属性简化为 gradient、gradientFrom 和 gradientTo 属性。这减少了解析渐变字符串的运行时性能成本,并允许更好的类型推断。
之前
<Box bgGradient="linear(to-r, red.200, pink.500)" />
之后
<Box bgGradient="to-r" gradientFrom="red.200" gradientTo="pink.500" />
颜色调色板
-
所有组件的默认颜色调色板现在是
gray,但您可以在主题中配置它。 -
默认主题颜色调色板的大小已增加到 11 种色调,以允许更多颜色变化。
之前
const colors = { // ... gray: { 50: "#F7FAFC", 100: "#EDF2F7", 200: "#E2E8F0", 300: "#CBD5E0", 400: "#A0AEC0", 500: "#718096", 600: "#4A5568", 700: "#2D3748", 800: "#1A202C", 900: "#171923", }, }之后
const colors = { // ... gray: { 50: { value: "#fafafa" }, 100: { value: "#f4f4f5" }, 200: { value: "#e4e4e7" }, 300: { value: "#d4d4d8" }, 400: { value: "#a1a1aa" }, 500: { value: "#71717a" }, 600: { value: "#52525b" }, 700: { value: "#3f3f46" }, 800: { value: "#27272a" }, 900: { value: "#18181b" }, 950: { value: "#09090b" }, }, }
样式属性
更改了一些样式属性的命名约定
noOfLines->lineClamptruncated->truncate_activeLink->_currentPage_activeStep->_currentStep_mediaDark->_osDark_mediaLight->_osLight
我们移除了 apply 属性,转而使用 textStyle 或 layerStyles
嵌套样式
我们改变了 Chakra UI 组件中编写嵌套样式的方式。
之前
使用 sx 或 __css 属性编写嵌套样式,有时无法获得嵌套样式的自动补全。
<Box
sx={{
svg: { color: "red.500" },
}}
/>
之后
使用 css 属性编写嵌套样式。所有嵌套选择器都需要使用 & 符号 & 前缀
<Box
css={{
"& svg": { color: "red.500" },
}}
/>
这样做有两个原因
- 更快的样式处理: 以前我们必须检查样式键是样式属性还是选择器,这总体上相当昂贵。
- 更好的类型: 这使得嵌套样式属性更易于强类型化
组件更改
ChakraProvider
-
移除了
theme属性,转而传递system属性。请导入defaultSystem模块而非theme -
移除了
resetCss属性,转而将preflight: false传递给createSystem函数
之前
<ChakraProvider resetCss={false}>
<Component />
</ChakraProvider>
之后
const system = createSystem(defaultConfig, { preflight: false })
<Provider value={system}>
<Component />
</Provider>
- 移除了对配置 toast 选项的支持。请改将它传递给
components/ui/toaster.tsx文件中的createToaster函数。
模态框
- 重命名为
Dialog - 移除
isCentered属性,转而使用placement=center属性 - 移除了
isOpen和onClose属性,转而使用open和onOpenChange属性
头像
- 移除
max属性,转而由用户控制 - 移除多余的标签部分
- 将与图片相关的属性移至
Avatar.Image组件 - 将回退图标移至
Avatar.Fallback组件 - 将
name属性移至Avatar.Fallback组件
Portal
- 移除
appendToParentPortal属性,转而使用containerRef - 移除
PortalManager组件
堆栈
- 将
spacing更改为gap - 移除了
StackItem,转而直接使用Box组件
折叠
- 将
Collapse重命名为Collapsible命名空间 - 将
in重命名为open animateOpacity已被移除,请改用关键帧动画expand-height和collapse-height
之前
<Collapse in={isOpen} animateOpacity>
Some content
</Collapse>
之后
<Collapsible.Root open={isOpen}>
<Collapsible.Content>Some content</Collapsible.Content>
</Collapsible.Root>
图像
- 现在渲染一个原生的
img,没有任何回退 - 由于其引起的 SSR 问题,移除了
fallbackSrc - 移除
useImage钩子 - 移除了
Img,转而直接使用Image组件
密码输入
- 将
value,defaultValue更改为使用string[]而不是string onChange属性现在称为onValueChange- 添加了新的
PinInput.Control和PinInput.Label组件部分 PinInput.Root现在默认渲染一个div元素。考虑与Stack或Group结合使用以获得更好的布局控制
数字输入
- 将
NumberInputStepper重命名为NumberInput.Control - 将
NumberInputStepperIncrement重命名为NumberInput.IncrementTrigger - 将
NumberInputStepperDecrement重命名为NumberInput.DecrementTrigger onChange属性现在称为onValueChange- 移除了
focusBorderColor和errorBorderColor,请考虑设置--focus-color和--error-colorCSS 变量
之前
<NumberInput>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
之后
<NumberInput.Root>
<NumberInput.Input />
<NumberInput.Control>
<NumberInput.IncrementTrigger />
<NumberInput.DecrementTrigger />
</NumberInput.Control>
</NumberInput.Root>
分隔线
- 重命名为
Separator - 切换到
div元素以获得更好的布局控制 - 简化组件,使其依赖于
borderTopWidth和borderInlineStartWidth - 要可靠地更改厚度,请设置
--divider-border-widthCSS 变量
输入框、选择框、文本域
- 移除了
invalid属性,转而将组件包裹在Field组件中。这允许轻松添加标签、错误文本和星号。
之前
<Input invalid />
之后
<Field.Root invalid>
<Field.Label>Email</Field.Label>
<Input />
<Field.ErrorText>This field is required</Field.ErrorText>
</Field.Root>
链接
- 移除了
isExternal属性,转而明确设置target和rel属性
之前
<Link isExternal>Click me</Link>
之后
<Link target="_blank" rel="noopener noreferrer">
Click me
</Link>
按钮
- 移除了
isActive,转而传递data-active
之前
<Button isActive>Click me</Button>
之后
<Button data-active>Click me</Button>
图标按钮
- 移除了
icon属性,转而直接渲染children属性 - 移除了
isRounded,转而使用borderRadius=full属性
加载指示器
- 将
thickness属性更改为borderWidth - 将
speed属性更改为animationDuration
之前
<Spinner thickness="2px" speed="0.5s" />
之后
<Spinner borderWidth="2px" animationDuration="0.5s" />