You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改MUI Stepper步骤图标样式并添加中间步骤

MUI Stepper 自定义图标样式与新增步骤实现方案

核心问题说明

原有写法.Mui-active': { color: '#1C6FC9', }不生效有两个原因:一是存在语法错误,类名后多写了单引号;二是裸写全局CSS类选择器优先级低于MUI组件内部默认样式,无法覆盖原生样式。

具体实现代码

1. 自定义步骤图标与连接线样式

使用MUI官方推荐的styledAPI覆写样式,分别匹配激活、已完成、未完成三种状态,配置目标蓝色#1C6FC9作为主色:

import * as React from 'react';
import { styled } from '@mui/material/styles';
import Check from '@mui/icons-material/Check';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import StepConnector, { stepConnectorClasses } from '@mui/material/StepConnector';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';

// 自定义步骤图标根节点
const CustomStepIconRoot = styled('div')(({ theme, ownerState }) => ({
  width: 32,
  height: 32,
  borderRadius: '50%',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: '#ccc',
  color: '#fff',
  zIndex: 1,
  // 激活态样式
  ...(ownerState.active && {
    backgroundColor: '#1C6FC9',
    boxShadow: '0 2px 6px rgba(28, 111, 201, 0.3)'
  }),
  // 已完成态样式
  ...(ownerState.completed && {
    backgroundColor: '#1C6FC9'
  })
}));

// 自定义步骤图标组件
const CustomStepIcon = (props) => {
  const { active, completed, className, icon } = props;
  const stepIcons = {
    1: 1,
    2: 2,
    3: 3,
    4: 4 // 可扩展对应新增的中间步骤
  };
  return (
    <CustomStepIconRoot ownerState={{ active, completed }} className={className}>
      {completed ? <Check fontSize="small" /> : stepIcons[String(icon)]}
    </CustomStepIconRoot>
  );
};

// 自定义步骤连接线
const CustomConnector = styled(StepConnector)(({ theme }) => ({
  [`&.${stepConnectorClasses.alternativeLabel}`]: {
    top: 15
  },
  [`&.${stepConnectorClasses.active}, &.${stepConnectorClasses.completed}`]: {
    [`& .${stepConnectorClasses.line}`]: {
      backgroundColor: '#1C6FC9'
    }
  },
  [`& .${stepConnectorClasses.line}`]: {
    height: 2,
    border: 'none',
    backgroundColor: '#eaeaf0',
    borderRadius: 1
  }
}));

2. 新增中间步骤

直接在步骤配置数组中插入需要的中间步骤即可,Stepper组件会自动根据数组长度渲染对应数量的步骤节点,示例步骤配置:

// 原步骤为2步,新增1个中间步骤后共3步,可按需扩展更多步骤
const steps = ['选择产品', '填写配置信息(新增中间步骤)', '提交订单'];

3. 组件使用示例

将自定义的图标、连接线传入Stepper组件即可生效:

export default function CustomStepper() {
  const [activeStep, setActiveStep] = React.useState(0);
  const [skipped, setSkipped] = React.useState(new Set());

  const isStepOptional = (step) => step === 1;
  const isStepSkipped = (step) => skipped.has(step);

  const handleNext = () => {
    let newSkipped = skipped;
    if (isStepSkipped(activeStep)) {
      newSkipped = new Set(newSkipped.values());
      newSkipped.delete(activeStep);
    }
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
    setSkipped(newSkipped);
  };

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1);
  };

  const handleSkip = () => {
    if (!isStepOptional(activeStep)) throw new Error("You can't skip a step that isn't optional.");
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
    setSkipped((prevSkipped) => {
      const newSkipped = new Set(prevSkipped.values());
      newSkipped.add(activeStep);
      return newSkipped;
    });
  };

  const handleReset = () => setActiveStep(0);

  return (
    <div style={{ width: '100%', padding: 24 }}>
      <Stepper activeStep={activeStep} connector={<CustomConnector />} alternativeLabel>
        {steps.map((label, index) => {
          const stepProps = {};
          const labelProps = {};
          if (isStepOptional(index)) labelProps.optional = <Typography variant="caption">可选</Typography>;
          if (isStepSkipped(index)) stepProps.completed = false;
          return (
            <Step key={label} {...stepProps}>
              <StepLabel StepIconComponent={CustomStepIcon} {...labelProps}>{label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
      {/* 步骤操作按钮与内容区域逻辑和原有写法一致 */}
      {activeStep === steps.length ? (
        <div style={{ marginTop: 32, textAlign: 'center' }}>
          <Typography>所有步骤已完成</Typography>
          <Button onClick={handleReset} sx={{ mt: 2 }}>重置</Button>
        </div>
      ) : (
        <div style={{ marginTop: 32, textAlign: 'center' }}>
          <Typography>步骤{activeStep + 1}内容区域</Typography>
          <div style={{ marginTop: 16 }}>
            <Button disabled={activeStep === 0} onClick={handleBack} sx={{ mr: 1 }}>上一步</Button>
            {isStepOptional(activeStep) && (
              <Button variant="contained" onClick={handleSkip} sx={{ mr: 1 }}>跳过</Button>
            )}
            <Button variant="contained" onClick={handleNext}>
              {activeStep === steps.length - 1 ? '完成' : '下一步'}
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}

注意事项

  • 不要直接写裸CSS类覆写MUI样式,优先使用sx、styled或主题覆写API,避免优先级问题
  • 新增步骤时只需要修改steps数组和CustomStepIcon内的stepIcons映射,不需要修改其他核心逻辑
  • 颜色、尺寸、阴影等样式可直接在CustomStepIconRoot和CustomConnector的配置中按需调整

内容的提问来源于stack exchange,提问作者Abdelkader

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:09:18