跳到主要内容
+

主题化组件

了解如何在主题级别将自定义样式应用于组件。

组件标识符

如果您之前使用过 Material UI,您可能对这种技术很熟悉。要在主题中自定义特定组件,请在 components 节点内指定组件标识符 (Joy{ComponentImportName})。

  • 使用 defaultProps 更改组件的默认 React props。
  • 使用 styleOverrides 将样式应用于每个组件插槽。
    • 每个 Joy UI 组件都包含 root 插槽。

访问 components.d.ts 文件以查看所有组件标识符。

import { CssVarsProvider, extendTheme } from '@mui/joy/styles';

const theme = extendTheme({
  components: {
    JoyChip: {
      defaultProps: {
        size: 'sm',
      },
      styleOverrides: {
        root: {
          borderRadius: '4px',
        },
      },
    },
  },
});

function App() {
  return <CssVarsProvider theme={theme}>...</CssVarsProvider>;
}

主题默认 props

在主题中指定为 defaultProps 的值会影响组件的所有实例

extendTheme({
  components: {
    JoyIconButton: {
      defaultProps: {
        variant: 'outlined',
        color: 'neutral',
      },
    },
  },
});

// This is the same as:
// <IconButton variant="outlined" color="neutral">
<IconButton>...</IconButton>;

主题样式覆盖

根据 props 更改样式

要更改给定 prop 的样式,请使用回调作为样式覆盖的值。该参数包含 themeownerState(props)。

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        // `ownerState` contains the component props and internal state
        root: ({ ownerState, theme }) => ({
          ...(ownerState.size === 'sm' && {
            borderRadius: theme.vars.radius.xs,
          }),
        }),
      },
    },
  },
});

我们建议使用来自 theme.vars.* 的 CSS 变量,因为它具有更好的调试体验,并且在某些情况下性能更高。

样式还可以包含任何 CSS 选择器(支持嵌套选择器),如下所示

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.variant === 'solid' &&
            ownerState.clickable && {
              color: 'rgba(255 255 255 / 0.72)',
              '&:hover': {
                color: '#fff',
              },
            }),
        }),
      },
    },
  },
});

根据状态更改样式

当 Joy UI 组件处于给定状态(例如 selecteddisabledfocusVisible 等)时,它们会增加样式的 CSS 特异性。

要覆盖特定状态的样式,请使用组件的类选择器,方法是导入其名称(驼峰式)后跟 Classes

import { listItemButtonClasses } from '@mui/joy/ListItemButton';

extendTheme({
  components: {
    JoyListItemButton: {
      styleOverrides: {
        root: {
          [`&.${listItemButtonClasses.selected}`]: {
            color: 'rgba(255 255 255 / 0.7)',
          },
        },
      },
    },
  },
});

可用的状态有:activecheckedcompleteddisablederrorexpandedfocusedfocusVisiblereadOnlyrequiredselected

扩展颜色

以下代码片段说明了如何为组件提供 primarysuccessinfodangerneutralwarning 之外的其他颜色。

请注意,通过创建新颜色,您将自动选择退出全局变体功能,该功能使您可以精细地控制 CSS 属性,如 colorbackgroundborder

下面的示例扩展了 Button 颜色以包括 secondary

extendTheme({
  components: {
    JoyButton: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.color === 'secondary' && {
            color: theme.vars.palette.text.secondary,
            backgroundColor: theme.vars.palette.background.level1,
          }),
        }),
      },
    },
  },
});

一旦这些值如上所述定义,您就可以直接在 Button 组件的实例上使用它们

<Button color="secondary">Secondary color</Button>
<Button color="tertiary">Tertiary color</Button>

TypeScript

需要模块扩展才能将值传递给组件的 color prop。

接口格式为 {ComponentName}PropsColorOverrides,这对于所有 Joy UI 组件都是相同的

// This part could be declared in your theme file
declare module '@mui/joy/Button' {
  interface ButtonPropsColorOverrides {
    secondary: true;
    tertiary: true;
  }
}

// typed-safe
<Button color="secondary" />
<Button color="tertiary" />

扩展尺寸

以下代码片段说明了如何为组件提供 smmdlg 之外的其他尺寸。我们建议遵循已建立的“T 恤尺寸”命名约定(例如 xsxlxxl 等),以保持与所有其他 props 的一致性。

下面的示例扩展了 Button 尺寸以包括 xsxl

extendTheme({
  components: {
    JoyButton: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.size === 'xs' && {
            '--Icon-fontSize': '1rem',
            '--Button-gap': '0.25rem',
            minHeight: 'var(--Button-minHeight, 1.75rem)',
            fontSize: theme.vars.fontSize.xs,
            paddingBlock: '2px',
            paddingInline: '0.5rem',
          }),
          ...(ownerState.size === 'xl' && {
            '--Icon-fontSize': '2rem',
            '--Button-gap': '1rem',
            minHeight: 'var(--Button-minHeight, 4rem)',
            fontSize: theme.vars.fontSize.xl,
            paddingBlock: '0.5rem',
            paddingInline: '2rem',
          }),
        }),
      },
    },
  },
});

一旦这些值如上所述定义,您就可以直接在 Button 组件的实例上使用它们

<Button size="xs">Extra small</Button>
<Button size="xl">Extra large</Button>

用于扩展尺寸的属性应仅与组件的密度或尺寸有关。要了解如何扩展变体属性,请查看本文档中的扩展变体部分。

TypeScript

需要模块扩展才能将值传递给组件的 size prop。

接口格式为 {ComponentName}PropsSizeOverrides,这对于所有 Joy UI 组件都是相同的

// This part could be declared in your theme file
declare module '@mui/joy/Button' {
  interface ButtonPropsSizeOverrides {
    xs: true;
    xl: true;
  }
}

// typed-safe
<Button size="xs" />
<Button size="xl" />

扩展变体

以下代码片段显示了如何扩展颜色属性的组件变体。请注意,通过创建新变体,您将自动选择退出全局变体功能,该功能使您可以精细地控制 CSS 属性,如 colorbackgroundborder

此示例扩展了 Sheet 变体以包括名为 glass 的自定义值

extendTheme({
  components: {
    JoySheet: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          ...(ownerState.variant === 'glass' && {
            color: theme.vars.palette.text.primary,
            background: 'rgba(255, 255, 255, 0.14)',
            backdropFilter: 'blur(5px)',
            border: '1px solid rgba(255, 255, 255, 0.3)',
            boxShadow: '0 4px 30px rgba(0, 0, 0, 0.1)',
          }),
        }),
      },
    },
  },
});

一旦值如上所述定义,您就可以直接在 Sheet 组件的实例上使用它

<Sheet variant="glass">Glassmorphism</Sheet>

TypeScript

需要模块扩展才能将值传递给组件的 variant prop。

接口格式为 {ComponentName}PropsSizeOverrides,这对于所有 Joy UI 组件都是相同的

// This part could be declared in your theme file
declare module '@mui/joy/Sheet' {
  interface SheetPropsVariantOverrides {
    glass: true;
  }
}

// typed-safe
<Sheet variant="glass" />;

每种模式的不同样式

要为每种模式(浅色和深色)指定与默认主题中定义的值不同的值,请使用 CSS 属性选择器。

Joy UI 将带有当前配色方案的 data-* 属性附加到 DOM(默认情况下为 HTML)。您可以使用 theme.getColorSchemeSelector 实用程序来更改组件样式。

下面的示例说明了如何在浅色模式下更改 boxShadow token 的强度,同时在深色模式下完全删除它

extendTheme({
  components: {
    JoyChip: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          // for the default color scheme (light)
          boxShadow: theme.vars.shadow.sm,

          // the result is `[data-joy-color-scheme="dark"] &`
          [theme.getColorSchemeSelector('dark')]: {
            boxShadow: 'none',
          },
        }),
      },
    },
  },
});

如果您定义了自定义配色方案,此方法也适用。但是,请注意,它会创建额外的 CSS 特异性,当父组件想要覆盖其子组件样式时,这可能会很麻烦。