Skip to Content
文档

秘诀

在 Chakra 中使用配方编写多变量样式。

概述

¥Overview

Chakra 提供了一种编写 CSS-in-JS 的方法,具有更好的性能、开发者体验和可组合性。其主要特性之一是能够使用类型安全的运行时 API 创建多变量样式。

¥Chakra provides a way to write CSS-in-JS with better performance, developer experience, and composability. One of its key features is the ability to create multi-variant styles with a type-safe runtime API.

配方包含以下属性:

¥A recipe consists of these properties:

  • className:要附加到组件的 className

  • base:组件的基本样式

  • variants:组件的不同视觉样式

  • compoundVariants:组件变体的不同组合

  • defaultVariants:组件的默认变体值

定义配方

¥Defining the recipe

使用 defineRecipe 标识函数创建配方。

¥Use the defineRecipe identity function to create a recipe.

button.recipe.ts

import { defineRecipe } from "@chakra-ui/react"

export const buttonRecipe = defineRecipe({
  base: {
    display: "flex",
  },
  variants: {
    visual: {
      solid: { bg: "red.200", color: "white" },
      outline: { borderWidth: "1px", borderColor: "red.200" },
    },
    size: {
      sm: { padding: "4", fontSize: "12px" },
      lg: { padding: "8", fontSize: "24px" },
    },
  },
})

使用配方

¥Using the recipe

在组件中,有两种方法可以使用配方:

¥There are two ways to use the recipe in a component:

  • 直接在带有 useRecipe 的组件中

  • 使用 chakra 工厂创建组件(推荐)

info

RSC 提示:由于它依赖于 React Hooks(例如 useContextuseInsertionEffect),因此需要添加 "use client" 指令。

¥RSC Tip: Adding the "use client" directive is required since it relies on react hooks like useContext and useInsertionEffect under the hood.

直接在组件中

¥Directly in component

使用 useRecipe 钩子获取组件的配方。然后,使用变体属性调用配方以获取样式。

¥Use the useRecipe hook to get the recipe for a component. Then, call the recipe with its variant props to get the styles.

button.tsx

"use client"

import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

export const Button = (props) => {
  const { visual, size, ...restProps } = props

  const recipe = useRecipe({ recipe: buttonRecipe })
  const styles = recipe({ visual, size })

  return <chakra.button css={styles} {...restProps} />
}

splitVariantProps

请注意 visualsize 属性是如何从要传递给配方的属性中解构出来的。更智能的方法是自动将配方属性与组件属性分离。

¥Notice how the visual and size props were destructured from the props to be passed to the recipe. A smarter approach would be to automatically split the recipe props from the component props.

为此,请使用 recipe.splitVariantProps 函数将配方属性与组件属性分离。

¥To do that, use the recipe.splitVariantProps function to split the recipe props from the component props.

button.tsx

"use client"

import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

export const Button = (props) => {
  const recipe = useRecipe({ recipe: buttonRecipe })
  const [recipeProps, restProps] = recipe.splitVariantProps(props)
  const styles = recipe(recipeProps)

  // ...
}

TypeScript

要推断配方变体属性的类型,请使用 RecipeVariantProps 类型助手。

¥To infer the recipe variant prop types, use the RecipeVariantProps type helper.

button.tsx

import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>

export interface ButtonProps
  extends React.PropsWithChildren<ButtonVariantProps> {}

创建组件

¥Creating a component

使用 chakra 函数根据配方创建组件。

¥Use the chakra function to create a component from a recipe.

注意:该配方也可以内联到 chakra 函数中。

button.tsx

"use client"

import { chakra } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

export const Button = chakra("button", buttonRecipe)

接下来,使用该组件并将配方属性传递给它。

¥Next, use the component and pass recipe properties to it.

app.tsx

import { Button } from "./button"

const App = () => {
  return (
    <Button visual="solid" size="lg">
      Click Me
    </Button>
  )
}

默认变量

¥Default Variants

defaultVariants 属性用于设置配方的默认变量值。当你想默认应用变体时,此功能非常有用。

¥The defaultVariants property is used to set the default variant values for the recipe. This is useful when you want to apply a variant by default.

button.tsx

"use client"

import { chakra } from "@chakra-ui/react"

const Button = chakra("button", {
  base: {
    display: "flex",
  },
  variants: {
    visual: {
      solid: { bg: "red.200", color: "white" },
      outline: { borderWidth: "1px", borderColor: "red.200" },
    },
    size: {
      sm: { padding: "4", fontSize: "12px" },
      lg: { padding: "8", fontSize: "24px" },
    },
  },
  defaultVariants: {
    visual: "solid",
    size: "lg",
  },
})

复合变体

¥Compound Variants

使用 compoundVariants 属性定义一组基于其他变体组合应用的变体。

¥Use the compoundVariants property to define a set of variants that are applied based on a combination of other variants.

button.tsx

"use client"

import { chakra } from "@chakra-ui/react"

const button = cva({
  base: {
    display: "flex",
  },
  variants: {
    visual: {
      solid: { bg: "red.200", color: "white" },
      outline: { borderWidth: "1px", borderColor: "red.200" },
    },
    size: {
      sm: { padding: "4", fontSize: "12px" },
      lg: { padding: "8", fontSize: "24px" },
    },
  },
  compoundVariants: [
    {
      size: "small",
      visual: "outline",
      css: {
        borderWidth: "2px",
      },
    },
  ],
})

当你同时使用 size="small"visual="outline" 变体时,compoundVariants 会将 css 属性应用于组件。

¥When you use the size="small" and visual="outline" variants together, the compoundVariants will apply the css property to the component.

app.tsx

<Button size="small" visual="outline">
  Click Me
</Button>

注意事项

¥Caveat

由于设计限制,无法使用具有响应式值的 compoundVariants

¥Due to the design constraints, using compoundVariants with responsive values doesn't work.

这意味着这样的代码将无法工作:

¥This means a code like this will not work:

<Button size={{ base: "sm", md: "lg" }} visual="outline">
  Click Me
</Button>

对于这些情况,我们建议使用不同的断点渲染组件的多个版本,然后根据需要隐藏/显示。

¥For this cases, we recommend rendering multiple versions of the component with different breakpoints, then hide/show as needed.

主题使用

¥Theme Usage

要以可重复使用配方的方式,请将其移至系统主题并将其添加到 theme.recipes 属性。

¥To use the recipe in a reusable manner, move it to the system theme and add it to theme.recipes property.

theme.ts

import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

const config = defineConfig({
  theme: {
    recipes: {
      button: buttonRecipe,
    },
  },
})

export default createSystem(defaultConfig, config)

TypeScript

使用 CLI 生成秘诀的类型。

¥Use the CLI to generate the types for the recipe.

npx @chakra-ui/cli typegen ./theme.ts

然后,将生成的类型导入到你的组件中。

¥Then, import the generated types in your component.

button.tsx

import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"

type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>

export interface ButtonProps
  extends React.PropsWithChildren<ButtonVariantProps> {}

更新代码

¥Update code

如果你直接在组件中使用配方,请更新 useRecipe 以使用 key 属性从主题中获取配方。

¥If you use the recipe directly in your component, update the useRecipe to use the key property to get the recipe from the theme.

button.tsx

const Button = () => {
-  const recipe = useRecipe({ recipe: buttonRecipe })
+  const recipe = useRecipe({ key: "button" })
  // ...
}

Previous

语义令牌

Next

插槽配方