Material UI 中通过 unstable_sxConfig 扩展与定制 sx prop 的实验性 API
sx prop 是 Material UI(MUI System)中基于主题的系统化样式入口,默认支持 p、m、bgcolor、borderRadius 等上百个工具类式的 key。但当你需要引入设计系统中的自定义语义 key(如 size),或者把某个 key 的取值范围约束到固定刻度(如只允许 sm/md/lg 的圆角)时,可以通过主题中的 unstable_sxConfig 实验性选项来扩展或改写 sx prop 的处理行为。本文基于仓库中 configure-the-sx-prop.md 文档展开,并对照 MUI System 源码说明每个配置项的真实处理链路,帮助你既能复制可运行的示例,又能理解其底层原理。
sx prop 的处理是配置驱动的
要理解 unstable_sxConfig 的作用位置,先看 sx 的核心实现。sx 样式函数由 unstable_createStyleFunctionSx() 创建,位于 styleFunctionSx.js:
// packages/mui-system/src/styleFunctionSx/styleFunctionSx.js
export function unstable_createStyleFunctionSx() {
function styleFunctionSx(props) {
// ...
const config = theme.unstable_sxConfig ?? defaultSxConfig; // L26
function process(sxInput) {
// 遍历 sx 对象的每个 key,逐 key 查找 config 中的处理规则
for (const styleKey in sxObject) {
// ...
if (config[styleKey]) {
setThemeValue(css, styleKey, value, theme, config); // L57
continue;
}
// 未命中 config 的 key 会尝试按断点对象或嵌套样式处理
}
}
}
}
关键点在第 26 行:sx 处理时优先读取 theme.unstable_sxConfig,找不到才回退到内置的 defaultSxConfig。也就是说,每个 key 如何映射 CSS,完全由一份 key → 处理规则的表驱动。默认表里登记了全部内置 key,例如:
// packages/mui-system/src/styleFunctionSx/defaultSxConfig.ts(节选)
const defaultSxConfig: SxConfig = {
border: { themeKey: 'borders', transform: borderTransform },
borderRadius: { themeKey: 'shape.borderRadius', style: borderRadius },
bgcolor: { themeKey: 'palette', cssProperty: 'backgroundColor', transform: paletteTransform },
p: { style: padding },
gap: { style: gap },
// ... 还有上百个 key
};
除了 sx prop 本身,组件级的系统 props(如 <Box p={4} />)也走同一份配置:extendSxProp.ts 中的 splitProps 会用 props?.theme?.unstable_sxConfig ?? defaultSxConfig 把传入的 props 拆分为"系统 props"(进入 sx 通道)与"其他 props"(透传给 DOM)。因此你扩展 config 后,组件 props 形式的系统 key 也会一并生效。
扩展 sx prop:新增自定义 key
文档给出的第一个场景:为 sx 增加一个新的 key。官方示例 ExtendTheSxProp.js 定义了一个 size key,表示"宽高相同的方形尺寸":
import { Box, handleBreakpoints } from '@mui/system';
import { createTheme, ThemeProvider } from '@mui/material/styles';
const customTheme = createTheme({
unstable_sxConfig: {
size: {
style: (props) => {
const { size, theme } = props;
const styleFromPropValue = (propValueFinal) => {
const value = theme.spacing(propValueFinal);
return {
width: value,
height: value,
};
};
// 添加对断点语法的 support
return handleBreakpoints(props, size, styleFromPropValue);
},
},
},
});
export default function ExtendTheSxProp() {
return (
<ThemeProvider theme={customTheme}>
<Box sx={{ size: 10, border: 1 }} />
</ThemeProvider>
);
}
要点解析:
size: 10的语义:10会经过theme.spacing(10)换算(默认 spacing 因子为 4,即 40px),最终生成width: 40px; height: 40px。- 为什么必须调用
handleBreakpoints:style函数是"最大自由度"的配置项,引擎不会替你处理断点——如果直接返回styleFromPropValue(size),sx={{ size: { xs: 4, md: 8 } }}这种响应式写法就无法工作。handleBreakpoints(props, propValue, styleFromPropValue)由 MUI System 从 breakpoints.ts 导出,并在 index.js 中作为公开 API 导出,仓库内borderRadius、gap、maxWidth等内置 style 函数(见 borders.ts、cssGrid.ts、sizing.ts)都是同样的写法,自定义 key 对齐这一模式即可。 - 文档目录中还提供了对应的 TypeScript 版本 ExtendTheSxProp.tsx,用于演示如何在类型层面同步扩展
SxProps,使size在 IDE 中获得类型提示。
覆盖已有行为:把 borderRadius 约束到固定刻度
文档的第二个场景:某些设计系统要求圆角只能取特定档位,而不是任意数字。默认配置中 borderRadius 是 { themeKey: 'shape.borderRadius', style: borderRadius }(见 defaultSxConfig.ts 第 36 行),允许任意数字、并支持响应式与嵌套。示例 ChangeTheBehaviorSxProp.js 通过替换该 key 的配置,让取值直接映射到 shape 主题上的命名刻度:
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
unstable_sxConfig: {
// 现在可以在 sx 中使用 borderRadius key,
// 直接从 palette(shape)取值
borderRadius: {
themeKey: 'shape',
},
},
shape: {
sm: 4,
md: 8,
lg: 12,
},
});
export default function ChangeTheBehaviorSxProp() {
return (
<Stack direction="row" sx={{ gap: 1 }}>
<ThemeProvider theme={theme}>
<Box sx={{ borderRadius: 'sm', border: 1, p: 4 }} />
<Box sx={{ borderRadius: 'md', border: 1, p: 4 }} />
<Box sx={{ borderRadius: 'lg', border: 1, p: 4 }} />
</ThemeProvider>
</Stack>
);
}
覆盖后 sx={{ borderRadius: 'sm' }} 的处理路径变为:themeKey: 'shape' 命中,引擎通过 getPath(theme, 'shape') 取出整个 shape 对象,再按 key 'sm' 查到 4,最终输出 border-radius: 4px。由于没有再提供 style/transform,数字与刻度的换算规则完全由你的 shape 主题决定——这正是"限制取值范围"的实现方式。
API 详解:unstable_sxConfig 的四个配置项
unstable_sxConfig 是一个 key 到配置对象的映射,类型定义见 SxConfigRecord:
// packages/mui-system/src/styleFunctionSx/defaultSxConfig.ts
export interface SxConfigRecord {
cssProperty?: keyof React.CSSProperties | false | undefined;
/** dot access in `Theme`(主题对象上的点路径) */
themeKey?: string | undefined;
transform?: TransformFunction | undefined;
style?: SimpleStyleFunction<any> | undefined;
}
export type SxConfig = Record<string, SxConfigRecord>;
文档 API 部分列出的四个属性与源码中 setThemeValue(styleFunctionSx.js 第 90–142 行)的处理顺序一一对应:
cssProperty(string | false,可选):声明输出到哪个 CSS 属性,默认与 key 同名。典型例子是bgcolor,其cssProperty为'backgroundColor'。取false时表示该 key 展开为任意样式片段(如默认的typography与displayPrint)。themeKey(string,可选):主题对象的点路径,如'shape.borderRadius'、'palette'。引擎用getPath(theme, themeKey)取到映射表后,按 key 查值;因此borderRadius: { themeKey: 'shape' }就能把'sm'这类命名刻度解析出来。transform(函数,可选):签名(cssValue, userValue) => number | string | React.CSSProperties | CSSObject,在最终写回 CSS 前对解析出的值做转换,典型用途如默认配置中palette的paletteTransform(把'primary.main'之类路径解析为实际色值)和border的borderTransform。style(函数,可选):签名(props) => CSSObject,接收{ [key]: 用户值, theme },返回完整样式对象,自由度最高。源码中它的优先级最高——setThemeValue里先判断style,存在则直接merge(css, style(...))后返回(第 109–119 行),不再走themeKey/transform路径。正因为它绕过了引擎的断点处理,文档和示例都强调要自行处理断点值(用handleBreakpoints)。
需要注意 style 与 themeKey/transform 的组合语义:给了 style 就只走 style;未给时 themeKey + transform + cssProperty 三者共同完成"查主题 → 变换 → 写 CSS 属性"的链路,并且该链路内部通过 iterateBreakpoints 天然支持响应式对象值。
合并机制:你的配置如何与默认配置合并
createTheme 对 unstable_sxConfig 的处理在 createTheme.js 第 39–42 行:
muiTheme.unstable_sxConfig = {
...defaultSxConfig,
...other?.unstable_sxConfig,
};
这是按 key 的浅合并,带来两条实用结论:
- 新增 key 不影响内置 key:
size这类新 key 只是往合并后的 config 里多加一项,p、m、bgcolor等全部保留,所以扩展示例中<Box sx={{ size: 10, border: 1 }} />的border依然是默认边框语义。 - 同名 key 完全替换而非深合并:示例中
borderRadius: { themeKey: 'shape' }会整体覆盖默认的{ themeKey: 'shape.borderRadius', style: borderRadius },原有的数字/响应式支持即被移除——这正是"改变已有行为"的底层原因。ThemeOptions与Theme的类型声明中也保留了该字段(见 createTheme.d.ts 第 35、51 行),而 Material 层的createTheme(如 createThemeNoVars.js)会将其透传给 MUI System 的建题逻辑。
适用前提与注意事项
- 实验性(unstable)前缀的含义:
unstable_sxConfig与unstable_sx均带unstable_前缀,位于 system 文档的实验性 API 分类下,意味着接口随版本演进可能变化,生产使用前建议锁定版本并回归验证样式输出。 - 依赖主题上下文:
styleFunctionSx中 config 取自props.theme(第 26 行),因此自定义 config 只在ThemeProvider提供的主题上生效;脱离主题的用法(如直接调用theme.unstable_sx)则依赖createTheme时合并进主题对象的配置(createTheme.js 第 43–48 行)。 style函数需自备断点能力:如前所述,使用style时必须调用handleBreakpoints,否则sx={{ size: { xs: 4, md: 8 } }}的响应式对象不会被展开。- 源码中的遗留特判:
setThemeValue中保留了themeKey === 'typography' && value === 'inherit'的兼容分支(第 103–107 行,代码注释标注待移除),说明该通道仍在迭代,进一步印证其实验性定位。
小结
unstable_sxConfig 提供了 MUI System 样式通道的两个对称能力:往 key → 规则表里加行(新增 size 这类语义 key),或改写某一行(把 borderRadius 收敛为固定刻度)。四个配置项中,themeKey/cssProperty/transform 组合适合"查主题 + 值变换"的常规映射,style 适合输出任意样式但需自行处理断点。结合 defaultSxConfig.ts 中内置 key 的写法,可以直接照着仓库源码为自己的设计系统补齐缺失的语义 key。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00