迁移到 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-themes
LightMode
、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
->open
defaultIsOpen
->defaultOpen
isDisabled
->disabled
isInvalid
->invalid
isRequired
->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
->lineClamp
truncated
->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-color
CSS 变量
之前
<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-width
CSS 变量
输入框、选择框、文本域
- 移除了
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" />