Skip to main content
Default Gray Amethyst

Wizard

<mo-wizard> | MOWizard
Since 2.2 stable

Wizards are a series of steps that guide users through a process.

Wizard is a disruptive modal component that guides users to achieve a goal through a series of steps in a defined order that require some user input. Long and complex tasks are divided into smaller parts and steps to simplify a process.

<mo-wizard orientation="horizontal">
  <mo-wizard-step label="Select case type"></mo-wizard-step>
  <mo-wizard-step label="Check details"></mo-wizard-step>
  <mo-wizard-step label="Fill in the form"></mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard orientation="horizontal">
      <MOWizardStep label="Select case type"></MOWizardStep>
      <MOWizardStep label="Check details"></MOWizardStep>
      <MOWizardStep label="Fill in the form"></MOWizardStep>
    </MOWizard>
  );
};

Examples

Vertical

By default the wizard steps are aligned in horizontal order. Use the attribute vertical to change the order to vertical instead.

Product overview Claim New
<mo-wizard orientation="vertical">
  <mo-wizard-step label="Select case type"></mo-wizard-step>
  <mo-wizard-step label="Check details">
    <mo-chip size="small" variant="neutral" pill slot="chips">Product overview</mo-chip>
    <mo-chip size="small" variant="neutral" pill slot="chips">Claim</mo-chip>
    <mo-chip size="small" variant="neutral" pill slot="chips">New</mo-chip>
  </mo-wizard-step>
  <mo-wizard-step label="Fill in the form"></mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard orientation="vertical">
      <MOWizardStep label="Select case type"></MOWizardStep>
      <MOWizardStep label="Check details">
        <MOChip size="small" variant="neutral" pill slot="chips">
          Product overview
        </MOChip>
        <MOChip size="small" variant="neutral" pill slot="chips">
          Claim
        </MOChip>
        <MOChip size="small" variant="neutral" pill slot="chips">
          New
        </MOChip>
      </MOWizardStep>
      <MOWizardStep label="Fill in the form"></MOWizardStep>
    </MOWizard>
  );
};

Non-linear

A non-linear wizard allows the user to freely navigate between the different steps, i.e., inactive steps are not set to disabled by default.

<mo-wizard nonLinear orientation="horizontal">
  <mo-wizard-step label="Select case type"></mo-wizard-step>
  <mo-wizard-step label="Check details"></mo-wizard-step>
  <mo-wizard-step label="Fill in the form"></mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard nonLinear orientation="horizontal">
      <MOWizardStep label="Select case type"></MOWizardStep>
      <MOWizardStep label="Check details"></MOWizardStep>
      <MOWizardStep label="Fill in the form"></MOWizardStep>
    </MOWizard>
  );
};

With chips

Use the chips slot to assign chips to each mo-wizard-step. Chips should be used to categorize and organize the steps.

Product overview Claim New
<mo-wizard orientation="horizontal">
  <mo-wizard-step label="Select case type">
    <mo-chip size="small" variant="neutral" pill slot="chips">Product overview</mo-chip>
    <mo-chip size="small" variant="neutral" pill slot="chips">Claim</mo-chip>
  </mo-wizard-step>
  <mo-wizard-step label="Check details"></mo-wizard-step>
  <mo-wizard-step label="Fill in the form">
    <mo-chip size="small" variant="neutral" pill slot="chips">New</mo-chip>
  </mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard orientation="horizontal">
      <MOWizardStep label="Select case type">
        <MOChip size="small" variant="neutral" pill slot="chips">
          Product overview
        </MOChip>
        <MOChip size="small" variant="neutral" pill slot="chips">
          Claim
        </MOChip>
      </MOWizardStep>
      <MOWizardStep label="Check details"></MOWizardStep>
      <MOWizardStep label="Fill in the form">
        <MOChip size="small" variant="neutral" pill slot="chips">
          New
        </MOChip>
      </MOWizardStep>
    </MOWizard>
  );
};

With sub steps

Use the default slot to assign sub-steps to each mo-wizard-step. Sub steps should be used to break down the step in to smaller pieces.

Vertical

Sub badge #1 Sub badge #2 New
<mo-wizard orientation="vertical">
  <mo-wizard-step label="Select case type">
    <mo-wizard-sub-step label="Sub step #1">
      <mo-badge variant="neutral" size="small" pill slot="badges">Sub badge #1</mo-badge>
      <mo-badge variant="neutral" size="small" pill slot="badges">Sub badge #2</mo-badge>
    </mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
  </mo-wizard-step>
  <mo-wizard-step label="Check details">
    <mo-wizard-sub-step label="Sub step #1"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #3"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #4"></mo-wizard-sub-step>
  </mo-wizard-step>
  <mo-wizard-step label="Fill in the form">
    <mo-chip size="small" variant="neutral" pill slot="chips">New</mo-chip>
  </mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard orientation="vertical">
      <MOWizardStep label="Select case type">
        <MOWizardSubStep label="Sub step #1">
          <MOBadge variant="neutral" size="small" pill slot="badges">
            Sub badge #1
          </MOBadge>
          <MOBadge variant="neutral" size="small" pill slot="badges">
            Sub badge #2
          </MOBadge>
        </MOWizardSubStep>
        <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
      </MOWizardStep>
      <MOWizardStep label="Check details">
        <MOWizardSubStep label="Sub step #1"></MOWizardSubStep>
        <MOWizardSubStep label="Sub step #2"></MOWizardSubStep>
        <MOWizardSubStep label="Sub step #3"></MOWizardSubStep>
        <MOWizardSubStep label="Sub step #4"></MOWizardSubStep>
      </MOWizardStep>
      <MOWizardStep label="Fill in the form">
        <MOChip size="small" variant="neutral" pill slot="chips">
          New
        </MOChip>
      </MOWizardStep>
    </MOWizard>
  );
};

Horizontal

New
<mo-wizard orientation="horizontal">
  <mo-wizard-step label="Select case type">
    <mo-wizard-sub-step label="Sub step #1"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #3"></mo-wizard-sub-step>
  </mo-wizard-step>
  <mo-wizard-step label="Check details">
    <mo-wizard-sub-step label="Sub step #1"></mo-wizard-sub-step>
    <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
  </mo-wizard-step>
  <mo-wizard-step label="Fill in the form">
    <mo-chip size="small" variant="neutral" pill slot="chips">New</mo-chip>
  </mo-wizard-step>
</mo-wizard>
import { MOWizard, MOWizardStep } from '@modes-web-components/dist/react';

const App = () => {
  return (
    <MOWizard orientation="horizontal">
      <MOWizardStep label="Select case type">
        <MOWizardSubStep label="Sub step #1">
          <MOWizardSubStep label="Sub step #1"></MOWizardSubStep>
          <MOWizardSubStep label="Sub step #2"></MOWizardSubStep>
          <MOWizardSubStep label="Sub step #3"></MOWizardSubStep>
        </MOWizardSubStep>
        <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
      </MOWizardStep>
      <MOWizardStep label="Check details">
        <MOWizardSubStep label="Sub step #1"></MOWizardSubStep>
        <MOWizardSubStep label="Sub step #2"></MOWizardSubStep>
      </MOWizardStep>
      <MOWizardStep label="Fill in the form">
        <MOChip size="small" variant="neutral" pill slot="chips">
          New
        </MOChip>
      </MOWizardStep>
    </MOWizard>
  );
};

Change step programmatically

Setting the attribute activeStep or calling the functions increment and decrement programmatically will automatically update the index of the wizard. Make sure you are setting the activeStep to a value between 0 and the number of slides. See example below on ways to access these attributes and states.

Previous Next
<mo-card style="width: 100%;">
  <mo-wizard slot="header" id="programmatic" orientation="horizontal">
    <mo-wizard-step label="Fill in the form"></mo-wizard-step>
    <mo-wizard-step label="Select case type"></mo-wizard-step>
    <mo-wizard-step label="Check details"></mo-wizard-step>
  </mo-wizard>
  <div style="display: flex; flex-direction: column; gap: 8px; padding: 1rem;">
    <mo-input label="Name"></mo-input>
    <mo-input label="Surname"></mo-input>
    <mo-input label="Address"></mo-input>
  </div>
  <div
    slot="footer"
    style="display: flex; padding-top: 16px; width: 100%; justify-content: space-between; align-items: center;"
  >
    <mo-button id="prev">Previous</mo-button>
    <mo-button id="next">Next</mo-button>
  </div>
</mo-card>
<script>
  const wizard = document.querySelector('#programmatic');
  const prev = document.querySelector('#prev');
  prev.disabled = wizard.activeStep === 0;
  const next = document.querySelector('#next');
  prev.addEventListener('click', () => {
    wizard.decrement();
  });
  next.addEventListener('click', () => {
    wizard.increment();
  });
  wizard.addEventListener('mo-change', () => {
    prev.disabled = wizard.activeStep === 0;
    next.disabled = wizard.activeStep === wizard.steps.length - 1;
  });
</script>
import { MOWizard, MOWizardStep, MOCard, MOInput, MOButton } from '@modes-web-components/dist/react';
import { useRef } from 'react';

const wizardRef = useRef(null);
const prevRef = useRef(null);
const nextRef = useRef(null);

const next = () => {
  wizardRef.increment();
};

const prev = () => {
  wizardRef.decrement();
};

const changeHandler = () => {
  prevRef.disabled = wizardRef.activeStep === 0;
  nextRef.disabled = wizardRef.activeStep === wizardRef.steps.length - 1;
};

const App = () => {
  return (
    <MOCard style={{ width: '100%' }}>
      <MOWizard onMoChange={changeHandler} slot="header" ref={wizardRef} orientation="horizontal">
        <MOWizardStep label="Fill in the form"></MOWizardStep>
        <MOWizardStep label="Select case type"></MOWizardStep>
        <MOWizardStep label="Check details"></MOWizardStep>
      </MOWizard>
      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', padding: '1rem' }}>
        <MOInput label="Name"></MOInput>
        <MOInput label="Surname"></MOInput>
        <MOInput label="Address"></MOInput>
      </div>
      <div
        slot="footer"
        style={{
          display: 'flex',
          paddingTop: '16px',
          width: '100%',
          justifyContent: 'space-between',
          alignItems: 'center'
        }}
      >
        <MOButton disabled={wizardRef.activeStep === 0} ref={prevRef} onClick={() => prev()}>
          Previous
        </MOButton>
        <MOButton ref={nextRef} onClick={() => next()}>
          Next
        </MOButton>
      </div>
    </MOCard>
  );
};

Mobile

When the parent container’s width is less than 320px, the mo-wizard will collapse into a dropdown element.

Previous Next
<mo-card style="width: 300px">
  <mo-wizard slot="header" id="mobile-wizard" orientation="horizontal">
    <mo-wizard-step label="Fill in the form"></mo-wizard-step>
    <mo-wizard-step label="Select case type">
      <mo-wizard-sub-step label="Sub step #1"></mo-wizard-sub-step>
      <mo-wizard-sub-step label="Sub step #2"></mo-wizard-sub-step>
    </mo-wizard-step>
    <mo-wizard-step label="Check details"></mo-wizard-step>
  </mo-wizard>
  <div style="display: flex; flex-direction: column; gap: 12px;">
    <mo-input label="Name"></mo-input>
    <mo-input label="Surname"></mo-input>
    <mo-input label="Address"></mo-input>
  </div>
  <div
    slot="footer"
    style="display: flex; padding-top: 16px; width: 100%; justify-content: space-between; align-items: center;"
  >
    <mo-button id="prev-mobile">Previous</mo-button>
    <mo-button id="next-mobile">Next</mo-button>
  </div>
</mo-card>
<script>
  const wizard = document.querySelector('#mobile-wizard');
  const prev = document.querySelector('#prev-mobile');
  prev.disabled = wizard.activeStep === 0;
  const next = document.querySelector('#next-mobile');
  prev.addEventListener('click', () => {
    wizard.decrement();
  });
  next.addEventListener('click', () => {
    wizard.increment();
  });
  wizard.addEventListener('mo-change', () => {
    prev.disabled = wizard.activeStep === 0;
    next.disabled = wizard.activeStep === wizard.steps.length - 1;
  });
</script>
import { MOWizard, MOWizardStep, MOCard, MOInput, MOButton } from '@modes-web-components/dist/react';
import { useRef } from 'react';

const wizardRef = useRef(null);
const prevRef = useRef(null);
const nextRef = useRef(null);

const next = () => {
  wizardRef.increment();
};

const prev = () => {
  wizardRef.decrement();
};

const changeHandler = () => {
  prevRef.disabled = wizardRef.activeStep === 0;
  nextRef.disabled = wizardRef.activeStep === wizardRef.steps.length - 1;
};

const App = () => {
  return (
    <MOCard style={{ width: '300px' }}>
      <MOWizard onMoChange={changeHandler} slot="header" ref={wizardRef} orientation="horizontal">
        <MOWizardStep label="Fill in the form"></MOWizardStep>
        <MOWizardStep label="Select case type"></MOWizardStep>
        <MOWizardStep label="Check details"></MOWizardStep>
      </MOWizard>
      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', padding: '1rem' }}>
        <MOInput label="Name"></MOInput>
        <MOInput label="Surname"></MOInput>
        <MOInput label="Address"></MOInput>
      </div>
      <div
        slot="footer"
        style={{
          display: 'flex',
          paddingTop: '16px',
          width: '100%',
          justifyContent: 'space-between',
          alignItems: 'center'
        }}
      >
        <MOButton disabled={wizardRef.activeStep === 0} ref={prevRef} onClick={() => prev()}>
          Previous
        </MOButton>
        <MOButton ref={nextRef} onClick={() => next()}>
          Next
        </MOButton>
      </div>
    </MOCard>
  );
};

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

Bundler React Script

To import this component using a bundler:

import '@metsooutotec/modes-web-components/dist/components/wizard/wizard.js';

To import this component as a React component:

import MOWizard from '@metsooutotec/modes-web-components/dist/react/wizard/';

To import this component using a script tag:

<script type="module" src="https://modes-web.metso.com/dist/components/cdn/components/wizard/wizard.js"></script>

Slots

Name Description
(default) The default slot. Use this to slot in mo-wizard-step elements.

Learn more about using slots.

Properties

Name Description Reflects Type Default
steps Query all child mo-wizard-step elements. MOWizardStep[] -
body Query for main wizard body, to show/hide it on mobile. HTMLDivElement -
activeStep Index of the currently active step. number 0
orientation The component orientation (layout flow direction). 'horizontal' | 'vertical' 'horizontal'
nonLinear Non-linear wizards allow the user to enter a multi-step flow at any point. boolean false
activeLabel tracks active label to give to mobile header string ''
nextLabel tracks next label to give to mobile header string ''
totalSteps length of the array of steps slotted in number 0
open open state of the mobile dropdown boolean false
prevWidth prevWidth to check if width changed in resize event number 0
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
mo-change onMoChange Emitted when the active step changes. -
mo-show onMoShow Emitted when the mobile dropdown is shown. -
mo-hide onMoHide Emitted when the mobile dropdown is hidden. -

Learn more about events.

Methods

Name Description Arguments
increment() increment active step by 1 -
decrement() decrement active step by 1 -
updateActiveStep() watch for changes in the activeStep, and update the steps in the default slot accordingly -
handleClick() toggle open state of the dropdown on mobile container sizes -
handleOpenChange() when the open state changes, play animation for the queried body -

Learn more about methods.

Parts

Name Description
base The component’s internal wrapper.

Learn more about customizing CSS parts.