Stepper
Install: npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
Version and compatibility
Pinned Mantine Core 9.7.1 requires React and React DOM ^19.2.0 and matching @mantine/hooks@9.7.1, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables theme.respectReducedMotion and uses forceColorScheme for light/dark.
Use case
Represent and select stages of a workflow.
Native props used by this example
These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.
| Component prop | Explanation |
|---|---|
Stepper.active | Active state/index, according to this component's type. |
Stepper.onStepClick | Requested step index; update active state after validating navigation. |
Stepper.Step.label | Visible label or component-specific label content. |
Interaction and state checks
Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.
Business integration boundary
Demo content/state is local, without server persistence, authorization or fetching. A static display component is not a completed business workflow.
Host setup
Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.
Runnable usage
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';
function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const [step, setStep] = useState(1);
return <M.Stepper active={step} onStepClick={setStep}><M.Stepper.Step label="Discover / 发现" /><M.Stepper.Step label="Preview / 预览" /><M.Stepper.Step label="Install / 安装" /></M.Stepper>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}
Preview states
Default
The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.
Usage
Allow step select
To disable step selection, set the allowStepSelect prop on the Stepper.Step component.
It can be used to prevent the user from reaching the next steps while letting them go back and forth between steps they've already reached before:
Disable next steps selection
Another way to disable the selection of upcoming steps is to use the allowNextStepsSelect directly on the Stepper component.
This is useful when you don't need to control the behavior specifically for each step.
Color, radius and size
Component size is controlled by two props: size and iconSize.
The size prop controls icon size, label and description font size.
iconSize allows you to overwrite the icon size separately from other size values:
With custom icons
You can replace the step icon by setting the icon prop on the Stepper.Step component.
To change the completed check icon, set completedIcon on the Stepper component.
You can use any React node as an icon: component, string, number:
You can use Stepper with icons only. Note that in this case, you will have to
set aria-label or title on the Stepper.Step component to make it accessible:
You can also change the completed icon for each step, for example, to indicate an error state:
Vertical orientation
Label position
Set labelPosition="bottom" to display the step label and description below the step icon:
Icon position
To change the step icon and body arrangement, set iconPosition="right":
Loading state
To indicate the loading state, set the loading prop on the Step component; the Loader will replace the step icon.
You can configure the default loader in the theme.
Examples of styles customization with Styles API:
<br />Get step ref
You can get refs of the step button and stepper root element (div):
import { useRef } from 'react';
import { Stepper } from '@mantine/core';
function MyStepper() {
const firstStep = useRef<HTMLButtonElement>(null);
const stepper = useRef<HTMLDivElement>(null);
return (
<Stepper ref={stepper} active={0}>
<Stepper.Step label="First step" ref={firstStep} />
<Stepper.Step label="Second step" />
</Stepper>
);
}
Wrap Stepper.Step
Stepper component relies on Stepper.Step order. Wrapping Stepper.Step is not supported.
Instead, you will need to use different approaches:
import { Stepper } from '@mantine/core';
// This will not work, step children will not render
function WillNotWork() {
return (
<Stepper.Step label="Nope" description="It will not work">
This part will not render
</Stepper.Step>
);
}
// Create a separate component for children
function WillWork() {
return <div>This will work as expected!</div>;
}
function Demo() {
return (
<Stepper active={1}>
<Stepper.Step label="Regular step">First step</Stepper.Step>
{/* Wrapped Stepper.Step will not render children, do not do that */}
<WillNotWork />
<Stepper.Step label="Step with custom content">
<WillWork />
</Stepper.Step>
<Stepper.Step label="Regular step">Third step</Stepper.Step>
</Stepper>
);
}
Accessibility
<Stepper.Step /> components render a button element; set aria-label or title props
to make the component visible for screen readers in case you do not specify label or description:
import { Stepper } from '@mantine/core';
function Demo() {
return (
<Stepper active={0}>
{/* Not ok, no label for screen reader */}
<Stepper.Step />
{/* Ok, label and description */}
<Stepper.Step label="Step 1" description="Create an account" />
{/* Ok, aria-label */}
<Stepper.Step aria-label="Create an account" />
</Stepper>
);
}
Keyboard Navigation
Stepper supports full keyboard navigation:
- Tab / Shift+Tab - Move focus between clickable steps
- Space / Enter - Activate the focused step
- Each step is a button element with proper ARIA attributes
Inactive steps that are not clickable are skipped during Tab navigation. The tabIndex is automatically managed based on whether a step is clickable or not.
Source-backed parameter reference
Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.
Stepper(_props)
export type StepFragmentComponent = React.FC<{ step: number }>;
export type StepperStylesNames =
| 'root'
| 'separator'
| 'steps'
| 'content'
| 'step'
| 'stepLoader'
| 'verticalSeparator'
| 'stepWrapper'
| 'stepIcon'
| 'stepCompletedIcon'
| 'stepIconContent'
| 'stepBody'
| 'stepLabel'
| 'stepDescription';
export type StepperCssVariables = {
root:
| '--stepper-color'
| '--stepper-icon-color'
| '--stepper-icon-size'
| '--stepper-content-padding'
| '--stepper-radius'
| '--stepper-fz'
| '--stepper-spacing';
};
export interface StepperProps
extends BoxProps, StylesApiProps<StepperFactory>, ElementProps<'div'> {
/** `Stepper.Step` components */
children: React.ReactNode;
/** Called when a clickable step is clicked with its 0-based index. Not called for the currently active step. */
onStepClick?: (stepIndex: number) => void;
/** Index of the active step */
active: number;
/** Step icon @default step index + 1 */
icon?: React.ReactNode | StepFragmentComponent;
/** Step icon displayed when step is completed @default CheckIcon */
completedIcon?: React.ReactNode | StepFragmentComponent;
/** Step icon displayed when step is in progress @default step index + 1 */
progressIcon?: React.ReactNode | StepFragmentComponent;
/** Key of `theme.colors` or any valid CSS color, controls colors of active and progress steps @default theme.primaryColor */
color?: MantineColor;
/** Controls size of the step icon, by default icon size is inferred from `size` prop */
iconSize?: number | string;
/** Key of `theme.spacing` or any valid CSS value to set `padding-top` of the content @default 'md' */
contentPadding?: MantineSpacing;
/** Stepper orientation @default 'horizontal' */
orientation?: 'vertical' | 'horizontal';
/** Icon position relative to the step body. Ignored if `labelPosition="bottom"` is set – with the label below the icon there is no left/right to place it on. @default 'left' */
iconPosition?: 'right' | 'left';
/** Controls size of various Stepper elements */
size?: MantineSize;
/** Key of `theme.radius` or any valid CSS value to set steps border-radius @default "xl" */
radius?: MantineRadius;
/** When true, users can click and jump to any step. When false, users can only navigate to completed steps @default true */
allowNextStepsSelect?: boolean;
/** Determines whether steps should wrap to the next line if no space is available @default true */
wrap?: boolean;
/** Controls position of the step label and description relative to the step icon. Takes precedence over `iconPosition`. Ignored if `orientation="vertical"` is set. @default 'right' */
labelPosition?: 'right' | 'bottom';
/** When true, automatically adjusts the icon color in completed steps to ensure sufficient contrast against the step background color */
autoContrast?: boolean;
/** If set, all step content is kept mounted. React 19 `Activity` is used to preserve state while content is hidden. @default false */
keepMounted?: boolean;
}
export type StepperFactory = Factory<{
props: StepperProps;
ref: HTMLDivElement;
stylesNames: StepperStylesNames;
vars: StepperCssVariables;
staticComponents: {
Step: typeof StepperStep;
Completed: typeof StepperCompleted;
};
}>;
export type Mod = Record<string, any> | string;
export type BoxMod = Mod | Mod[] | BoxMod[];
export interface BoxProps extends MantineStyleProps {
/** Class added to the root element, if applicable */
className?: string | undefined;
/** Inline style added to root component element, can subscribe to theme defined on MantineProvider */
style?: MantineStyleProp;
/** CSS variables defined on root component element */
__vars?: CssVarsProp;
/** `size` property passed down the HTML element */
__size?: string;
/** Breakpoint above which the component is hidden with `display: none` */
hiddenFrom?: MantineBreakpoint;
/** Breakpoint below which the component is hidden with `display: none` */
visibleFrom?: MantineBreakpoint;
/** Determines whether component should be hidden in light color scheme with `display: none` */
lightHidden?: boolean;
/** Determines whether component should be hidden in dark color scheme with `display: none` */
darkHidden?: boolean;
/** Element modifiers transformed into `data-` attributes, for example, `{ 'data-size': 'xl' }`, falsy values are removed */
mod?: BoxMod;
}
export type ElementProps<
ElementType extends React.ElementType,
PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;
export interface CSSProperties extends React.CSSProperties {
[key: string]: any;
}
type MantineStyle = CSSProperties | ((theme: MantineTheme) => CSSProperties);
export type MantineStyleProp = MantineStyle | MantineStyle[] | MantineStyleProp[] | undefined;
export type CssVariable = `--${string}`;
export type CssVariables<Variable extends string = CssVariable> = Partial<Record<Variable, string>>;
export type CssVars<Variable extends string = CssVariable> =
| CssVariables<Variable>
| ((theme: MantineTheme) => CssVariables<Variable>)
| CssVars<Variable>[];
export type CssVarsProp<Variable extends string = CssVariable> =
| CssVars<Variable>
| CssVars<Variable>[];
Native and external types
External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.
Factory<{
props: StepperProps;
ref: HTMLDivElement;
stylesNames: StepperStylesNames;
vars: StepperCssVariables;
staticComponents: {
Step: typeof StepperStep;
Completed: typeof StepperCompleted;
};
}>
MantineStyleProps
React.CSSProperties
MantineTheme
Partial<Record<Variable, string>>
Record<Variable, string>
Variable
MantineBreakpoint
Record<string, any>
StylesApiProps<StepperFactory>
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
React.ReactNode
React.FC<{ step: number }>
MantineColor
MantineSpacing
MantineSize
MantineRadius
HTMLDivElement