如何消除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图标造成额外偏移。调整以下几点即可解决:
- 重置Step组件的内边距:去掉上下多余padding,让图标和连接线垂直对齐
- 调整StepConnector的连接线位置:让线对齐图标的中心,隐藏默认的connector图标
- 完善步骤状态管理:确保
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
相关产品推荐
相关产品推荐

