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

如何消除MUI V5 Stepper组件图标与连接线的间距

MUI V5垂直Stepper:消除步骤图标与连接线的间距

当前垂直Stepper组件中,步骤图标与左侧连接线之间存在多余间距,目标是让连接线直接贴合图标边缘,实现紧凑的视觉效果。

问题代码

import * as React from "react";
import Box from "@mui/material/Box";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import { StepLabel, StepConnector } from "@mui/material";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import RadioButtonCheckedIcon from "@mui/icons-material/RadioButtonChecked";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import CircleOutlinedIcon from "@mui/icons-material/CircleOutlined";

const steps = [
  {
    label: "Trade-in started",
    description: `04/01/2023`
  },
  {
    label: "Device inspected"
  },
  {
    label: "Trade-in complete (credit pending)"
  }
];

const ActiveStepIcon = styled(RadioButtonCheckedIcon)(({ theme }) => ({
  color: "black"
}));

const NonActiveStepIcon = styled(CircleOutlinedIcon)(({ theme }) => ({
  color: "grey"
}));

const CompletedStepIcon = styled(CheckCircleIcon)(({ theme }) => ({
  color: "black"
}));

const CustomStepConnector = styled(StepConnector)(({ theme }) => ({
  "& .MuiStepConnector-line": {
    minHeight: "131px",
    borderLeft: "2.5px solid black" // Add a border to simulate the line
  },
  "& .MuiStepConnector-icon": {
    marginLeft: "-12px" // Adjust this value as needed to control the spacing
  }
}));

export default function VerticalLinearStepper() {
  const [activeStep, setActiveStep] = React.useState(0);

  const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
  };

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

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

  return (
    <Box sx={{ maxWidth: 400 }}>
      <Stepper
        activeStep={activeStep}
        orientation="vertical"
        connector={<CustomStepConnector />}
      >
        {steps.map((step, index) => {
          const stepProps = {};
          const labelProps = {
            StepIconComponent:
              activeStep === index
                ? ActiveStepIcon
                : steps[index].completed
                ? CompletedStepIcon
                : NonActiveStepIcon
          };
          if (index === 0) {
            labelProps.optional = (
              <Typography variant="caption">{step.description}</Typography>
            );
          }
          return (
            <Step key={step.label} {...stepProps}>
              <StepLabel {...labelProps}>{step.label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
    </Box>
  );
}

尝试过的无效操作

  • 移除MuiStep-root和MuiStepLabel-root的内边距、外边距
  • 为MuiStepConnector-root设置最小高度

解决方案

问题根源在于MUI垂直Stepper的默认样式:Step组件有上下内边距,StepConnector的连接线位置未对齐图标中心,且默认的connector图标造成额外偏移。调整以下几点即可解决:

  1. 重置Step组件的内边距:去掉上下多余padding,让图标和连接线垂直对齐
  2. 调整StepConnector的连接线位置:让线对齐图标的中心,隐藏默认的connector图标
  3. 完善步骤状态管理:确保completed状态正确更新,图标切换逻辑正常

修改后的完整代码

import * as React from "react";
import Box from "@mui/material/Box";
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import { StepLabel, StepConnector } from "@mui/material";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import RadioButtonCheckedIcon from "@mui/icons-material/RadioButtonChecked";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import CircleOutlinedIcon from "@mui/icons-material/CircleOutlined";

export default function VerticalLinearStepper() {
  // 初始化步骤时添加completed状态
  const [steps, setSteps] = React.useState([
    {
      label: "Trade-in started",
      description: `04/01/2023`,
      completed: false,
    },
    {
      label: "Device inspected",
      completed: false,
    },
    {
      label: "Trade-in complete (credit pending)",
      completed: false,
    }
  ]);

  const [activeStep, setActiveStep] = React.useState(0);

  const ActiveStepIcon = styled(RadioButtonCheckedIcon)(({ theme }) => ({
    color: "black",
    width: 24,
    height: 24,
  }));

  const NonActiveStepIcon = styled(CircleOutlinedIcon)(({ theme }) => ({
    color: "grey",
    width: 24,
    height: 24,
  }));

  const CompletedStepIcon = styled(CheckCircleIcon)(({ theme }) => ({
    color: "black",
    width: 24,
    height: 24,
  }));

  const CustomStepConnector = styled(StepConnector)(({ theme }) => ({
    // 重置默认margin,让连接线紧贴Step
    marginLeft: 0,
    "& .MuiStepConnector-line": {
      // 去掉固定minHeight,自适应内容高度
      minHeight: "auto",
      borderLeft: "2.5px solid black",
      // 让连接线从图标中心位置延伸(图标默认24px,top/bottom设为12px)
      top: 12,
      bottom: 12,
      // 对齐图标中心(图标宽度24px,marginLeft设为12px)
      marginLeft: 12,
    },
    // 隐藏默认的connector图标,避免额外偏移
    "& .MuiStepConnector-icon": {
      display: "none",
    },
  }));

  const handleNext = () => {
    setActiveStep(prev => {
      // 更新上一步的completed状态
      if (prev < steps.length - 1) {
        const updatedSteps = [...steps];
        updatedSteps[prev].completed = true;
        setSteps(updatedSteps);
      }
      return prev + 1;
    });
  };

  const handleBack = () => {
    setActiveStep(prev => {
      // 返回时重置当前步骤的completed状态
      if (prev > 0) {
        const updatedSteps = [...steps];
        updatedSteps[prev].completed = false;
        setSteps(updatedSteps);
      }
      return prev - 1;
    });
  };

  const handleReset = () => {
    setActiveStep(0);
    // 重置所有步骤的completed状态
    setSteps(prev => prev.map(step => ({...step, completed: false})));
  };

  return (
    <Box sx={{ maxWidth: 400, padding: 2 }}>
      <Stepper
        activeStep={activeStep}
        orientation="vertical"
        connector={<CustomStepConnector />}
        // 重置Stepper的默认padding
        sx={{ paddingLeft: 0 }}
      >
        {steps.map((step, index) => {
          const labelProps = {
            StepIconComponent:
              activeStep === index
                ? ActiveStepIcon
                : step.completed
                ? CompletedStepIcon
                : NonActiveStepIcon,
            // 调整图标与文字的间距
            sx: { "& .MuiStepIcon-root": { marginRight: 1.5 } }
          };
          if (index === 0) {
            labelProps.optional = (
              <Typography variant="caption">{step.description}</Typography>
            );
          }
          return (
            <Step 
              key={step.label} 
              // 去掉Step上下多余内边距,让连接线紧贴图标
              sx={{ paddingY: 1, paddingLeft: 0 }}
            >
              <StepLabel {...labelProps}>{step.label}</StepLabel>
            </Step>
          );
        })}
      </Stepper>
      {/* 添加操作按钮方便测试 */}
      <Box sx={{ marginTop: 2 }}>
        <Button
          disabled={activeStep === 0}
          onClick={handleBack}
          sx={{ marginRight: 1 }}
        >
          Back
        </Button>
        <Button
          variant="contained"
          color="primary"
          onClick={handleNext}
          disabled={activeStep === steps.length}
        >
          {activeStep === steps.length ? "Finish" : "Next"}
        </Button>
        <Button onClick={handleReset} sx={{ marginLeft: 1 }}>
          Reset
        </Button>
      </Box>
    </Box>
  );
}

关键调整说明

  • CustomStepConnector:移除默认的connector图标,调整连接线的top/bottom/marginLeft,让线对齐图标的中心位置
  • Step组件:设置paddingY:1减少上下内边距,paddingLeft:0去掉左侧默认padding
  • 步骤状态:完善completed状态的更新逻辑,确保图标切换正确
  • 图标样式:固定图标尺寸为24px,保证对齐一致性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:14:57