---
id: Wizard
section: components
cssPrefix: pf-c-wizard
propComponents: ['Wizard', 'WizardNav', 'WizardNavItem', 'WizardHeader', 'WizardBody', 'WizardFooter', 'WizardToggle']
---

import { Button, Wizard, WizardFooter, WizardContextConsumer, ModalVariant, Alert, EmptyState, EmptyStateIcon, EmptyStateBody, EmptyStateSecondaryActions, Title, Progress } from '@patternfly/react-core';
import ExternalLinkAltIcon from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
import SlackHashIcon from '@patternfly/react-icons/dist/js/icons/slack-hash-icon';
import FinishedStep from './FinishedStep';
import SampleForm from './SampleForm';

## Examples
### Basic
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';

class SimpleWizard extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const steps = [
      { name: 'First step', component: <p>Step 1 content</p> },
      { name: 'Second step', component: <p>Step 2 content</p> },
      { name: 'Third step', component: <p>Step 3 content</p> },
      { name: 'Fourth step', component: <p>Step 4 content</p> },
      { name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
    ];
    const title = 'Basic wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        steps={steps}
        height={400}
      />
    );
  }
}
```

### Anchors for nav items
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';
import ExternalLinkAltIcon from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
import SlackHashIcon from '@patternfly/react-icons/dist/js/icons/slack-hash-icon';

class WizardWithNavAnchors extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const steps = [
      {
        name: <div><ExternalLinkAltIcon /> PF3</div>,
        component: <p>Step 1: Read about PF3</p>,
        stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v3/', target: '_blank' }
      },
      {
        name: <div><ExternalLinkAltIcon /> PF4</div>,
        component: <p>Step 2: Read about PF4</p>,
        stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v4/', target: '_blank' }
      },
      {
        name: <div><SlackHashIcon /> Join us on slack</div>,
        component: <Button variant="link" component="a" target="_blank" href="https://patternfly.slack.com/">Join the conversation</Button>,
        stepNavItemProps: { navItemComponent: 'a', href: 'https://patternfly.slack.com/', target: '_blank' }
      }
    ];
    const title = 'Anchor link wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        steps={steps}
        height={400}
      />
    );
  }
}
```

### Incrementally enabled steps
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';

class IncrementallyEnabledStepsWizard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stepIdReached: 1
    };
    this.onNext = ({ id }) => {
      this.setState({
        stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
      });
    };
    this.closeWizard = () => {
      console.log("close wizard");
    }
  }

  render() {
    const { stepIdReached } = this.state;

    const steps = [
      { id: 1, name: 'First step', component: <p>Step 1 content</p> },
      { id: 2, name: 'Second step', component: <p>Step 2 content</p>, canJumpTo: stepIdReached >= 2 },
      { id: 3, name: 'Third step', component: <p>Step 3 content</p>, canJumpTo: stepIdReached >= 3 },
      { id: 4, name: 'Fourth step', component: <p>Step 4 content</p>, canJumpTo: stepIdReached >= 4 },
      { id: 5, name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish', canJumpTo: stepIdReached >= 5 }
    ];
    const title = 'Incrementally enabled wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        onClose={this.closeWizard}
        steps={steps}
        onNext={this.onNext}
        height={400}
      />
    );
  }
}
```

### Finished
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';
import FinishedStep from './examples/FinishedStep';

class FinishedStepWizard extends React.Component {
  constructor(props) {
    super(props);

    this.closeWizard = () => {
      console.log("close wizard");
    }
  }

  render() {

    const steps = [
      { name: 'First step', component: <p>Step 1 content</p> },
      { name: 'Second step', component: <p>Step 2 content</p> },
      { name: 'Third step', component: <p>Step 3 content</p> },
      { name: 'Fourth step', component: <p>Step 4 content</p> },
      { name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' },
      { name: 'Finish', component: <FinishedStep onClose={this.closeWizard} />, isFinishedStep: true }
    ];
    const title = 'Finished wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        onClose={this.closeWizard}
        steps={steps}
        height={400}
      />
    );
  }
}
```

### Enabled on form validation
```js
import React from 'react';
import { Button, Wizard, Form, FormGroup, TextInput } from '@patternfly/react-core';
import SampleForm from './examples/SampleForm';

class ValidationWizard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isFormValid: false,
      formValue: 'Thirty',
      allStepsValid: false,
      stepIdReached: 1
    };

    this.closeWizard = () => {
      console.log("close wizard");
    }

    this.onFormChange = (isValid, value) => {
      this.setState(
        {
          isFormValid: isValid,
          formValue: value
        },
        this.areAllStepsValid
      );
    };

    this.areAllStepsValid = () => {
      this.setState({
        allStepsValid: this.state.isFormValid
      });
    };

    this.onNext = ({ id, name }, { prevId, prevName }) => {
      console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
      this.setState({
        stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
      });
      this.areAllStepsValid();
    };

    this.onBack = ({ id, name }, { prevId, prevName }) => {
      console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
      this.areAllStepsValid();
    };

    this.onGoToStep = ({ id, name }, { prevId, prevName }) => {
      console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
    };

    this.onSave = () => {
      console.log('Saved and closed the wizard');
      this.setState({
        isOpen: false
      });
    };
  }

  render() {
    const { isFormValid, formValue, allStepsValid, stepIdReached } = this.state;

    const steps = [
      { id: 1, name: 'Information', component: <p>Step 1 content</p> },
      {
        name: 'Configuration',
        steps: [
          {
            id: 2,
            name: 'Substep A with validation',
            component: (
              <SampleForm formValue={formValue} isFormValid={isFormValid} onChange={this.onFormChange} />
            ),
            enableNext: isFormValid,
            canJumpTo: stepIdReached >= 2
          },
          { id: 3, name: 'Substep B', component: <p>Substep B</p>, canJumpTo: stepIdReached >= 3 }
        ]
      },
      { id: 4, name: 'Additional', component: <p>Step 3 content</p>, enableNext: allStepsValid, canJumpTo: stepIdReached >= 4 },
      { id: 5, name: 'Review', component: <p>Step 4 content</p>, nextButtonText: 'Close', canJumpTo: stepIdReached >= 5 }
    ];
    const title = 'Enabled on form validation wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        onClose={this.closeWizard}
        onSave={this.onSave}
        steps={steps}
        onNext={this.onNext}
        onBack={this.onBack}
        onGoToStep={this.onGoToStep}
        height={400}
      />
    );
  }
}
```

### Validate on button press
```js
import React from 'react';
import { Button, Wizard, WizardFooter, WizardContextConsumer, Alert } from '@patternfly/react-core';
import SampleForm from './examples/SampleForm';
import FinishedStep from './examples/FinishedStep';

class ValidateButtonPressWizard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stepsValid: 0
    };

    this.closeWizard = () => {
      console.log("close wizard");
    }

    this.validateLastStep = onNext => {
      const { stepsValid } = this.state;
      if (stepsValid !== 1) {
        this.setState({
          stepsValid: 1
        });
      } else {
        onNext();
      }
    };
  }

  render() {
    const { stepsValid } = this.state;

    const steps = [
      { name: 'First step', component: <p>Step 1 content</p> },
      { name: 'Second step', component: <p>Step 2 content</p> },
      {
        name: 'Final Step',
        component: (
          <>
            {stepsValid === 1 && <div style={{padding: '15px 0'}}><Alert variant="warning" title="Validation failed, please try again" /></div>}
            <SampleForm formValue="Validating on button press" isFormValid={stepsValid !== 1} />
          </>
        )
      },
      { name: 'Finish', component: <FinishedStep onClose={this.closeWizard} />, isFinishedStep: true }
    ];

    const CustomFooter = (
      <WizardFooter>
        <WizardContextConsumer>
          {({ activeStep, goToStepByName, goToStepById, onNext, onBack, onClose }) => {
            if (activeStep.name !== 'Final Step') {
              return (
                <>
                  <Button variant="primary" type="submit" onClick={onNext}>
                    Forward
                  </Button>
                  <Button variant="secondary" onClick={onBack} className={activeStep.name === 'Step 1' ? 'pf-m-disabled' : ''}>
                    Backward
                  </Button>
                  <Button variant="link" onClick={onClose}>
                    Cancel
                  </Button>
                </>
              )
            }
            // Final step buttons
            return (
              <>
                <Button onClick={() => this.validateLastStep(onNext)}>Validate</Button>
                <Button onClick={() => goToStepByName('Step 1')}>Go to Beginning</Button>
              </>
            )}}
        </WizardContextConsumer>
      </WizardFooter>
    );
    const title = 'Validate on button press wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        onClose={this.closeWizard}
        footer={CustomFooter}
        steps={steps}
        height={400}
      />
    );
  }
}
```

### Progressive steps
```js
import React from 'react';
import { Button, Radio, Wizard, WizardFooter, WizardContextConsumer, Alert } from '@patternfly/react-core';
import SampleForm from './examples/SampleForm';
import FinishedStep from './examples/FinishedStep';

class ProgressiveWizard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      showCreateStep: false,
      showUpdateStep: false,
      showOptionsStep: false,
      showReviewStep: false,
      getStartedStepRadio: 'Create',
      createStepRadio: 'Quick',
      updateStepRadio: 'Quick'
    };
    this.closeWizard = () => {
      console.log("close wizard");
    }
    this.onGoToStep = ({ id, name }, { prevId, prevName }) => {
      // Remove steps after the currently clicked step
      if (name === 'Get Started') {
        this.setState({
          showReviewStep: false,
          showOptionsStep: false,
          showCreateStep: false,
          showUpdateStep: false
        });
      } else if (name === 'Create Options' || name === 'Update Options') {
        this.setState({
          showReviewStep: false,
          showOptionsStep: false
        });
      } else if (name.indexOf('Substep') > -1) {
        this.setState({
          showReviewStep: false
        });
      }
    };
    this.getNextStep = (activeStep, callback) => {
      if (activeStep.name === 'Get Started') {
        if (this.state.getStartedStepRadio === 'Create') {
          this.setState({
            showCreateStep: true,
            showUpdateStep: false,
            showOptionsStep: false,
            showReviewStep: false
          }, () => {
            callback();
          });
        } else {
          this.setState({
            showCreateStep: false,
            showUpdateStep: true,
            showOptionsStep: false,
            showReviewStep: false
          }, () => {
            callback();
          });
        }
      } else if (activeStep.name === 'Create Options' || activeStep.name === 'Update Options') {
        this.setState({
          showOptionsStep: true,
          showReviewStep: false
        }, () => {
          callback();
        });
      } else if (activeStep.name === 'Substep 3') {
        this.setState({
          showReviewStep: true
        }, () => {
          callback();
        });
      } else {
        callback();
      }
    };
    this.getPreviousStep = (activeStep, callback) => {
      if (activeStep.name === 'Review') {
        this.setState({
          showReviewStep: false
        }, () => {
          callback();
        });
      } else if (activeStep.name === 'Substep 1') {
        this.setState({
          showOptionsStep: false
        }, () => {
          callback();
        });
      } else if (activeStep.name === 'Create Options') {
        this.setState({
          showCreateStep: false
        }, () => {
          callback();
        });
      } else if (activeStep.name === 'Update Options') {
        this.setState({
          showUpdateStep: false
        }, () => {
          callback();
        });
      } else {
        callback();
      }
    };
  }

  render() {
    const {
      stepsValid,
      getStartedStepRadio,
      createStepRadio,
      updateStepRadio,
      showCreateStep,
      showUpdateStep,
      showOptionsStep,
      showReviewStep
    } = this.state;

    const getStartedStep = {
      name: 'Get Started',
      component: (
        <div>
          <Radio
            value="Create"
            isChecked={getStartedStepRadio === 'Create'}
            onChange={(_, event) => this.setState({ getStartedStepRadio: event.currentTarget.value })}
            label="Create a new thing"
            name="radio-step-start"
            id="radio-step-start-1"
          />{' '}
          <Radio
            value="Update"
            isChecked={getStartedStepRadio === 'Update'}
            onChange={(_, event) => this.setState({ getStartedStepRadio: event.currentTarget.value })}
            label="Update an existing thing"
            name="radio-step-start"
            id="radio-step-start-2"
          />
        </div>
      )
    };

    const createStep = {
      name: 'Create Options',
      component: (
        <div>
          <Radio
            value="Quick"
            isChecked={createStepRadio === 'Quick'}
            onChange={(_, event) => this.setState({ createStepRadio: event.currentTarget.value })}
            label="Quick Create"
            name="radio-step-create"
            id="radio-step-create-1"
          />{' '}
          <Radio
            value="Custom"
            isChecked={createStepRadio === 'Custom'}
            onChange={(_, event) => this.setState({ createStepRadio: event.currentTarget.value })}
            label="Custom Create"
            name="radio-step-create"
            id="radio-step-create-2"
          />
        </div>
      )
    };

    const updateStep = {
      name: 'Update Options',
      component: (
        <div>
          <Radio
            value="Quick"
            isChecked={updateStepRadio === 'Quick'}
            onChange={(_, event) => this.setState({ updateStepRadio: event.currentTarget.value })}
            label="Quick Update"
            name="radio-step-update"
            id="radio-step-update-1"
          />{' '}
          <Radio
            value="Custom"
            isChecked={updateStepRadio === 'Custom'}
            onChange={(_, event) => this.setState({ updateStepRadio: event.currentTarget.value })}
            label="Custom Update"
            name="radio-step-update"
            id="radio-step-update-2"
          />
        </div>
      )
    };

    const optionsStep = {
      name: showCreateStep ? `${createStepRadio} Options` : `${updateStepRadio} Options`,
      steps: [
        {
          name: 'Substep 1',
          component: 'Substep 1'
        },
        {
          name: 'Substep 2',
          component: 'Substep 2'
        },
        {
          name: 'Substep 3',
          component: 'Substep 3'
        }
      ]
    };

    const reviewStep = {
      name: 'Review',
      component: (
        <div>
          <div>First choice: {getStartedStepRadio}</div>
          <div>Second choice: {showCreateStep ? createStepRadio : updateStepRadio}</div>
        </div>
      )
    };

    const steps = [
      getStartedStep,
      ...(showCreateStep ? [createStep] : []),
      ...(showUpdateStep ? [updateStep] : []),
      ...(showOptionsStep ? [optionsStep] : []),
      ...(showReviewStep ? [reviewStep] : []),
    ];

    const CustomFooter = (
      <WizardFooter>
        <WizardContextConsumer>
          {({ activeStep, goToStepByName, goToStepById, onNext, onBack, onClose }) => {
            return (
              <>
                <Button variant="primary" type="submit" onClick={() => this.getNextStep(activeStep, onNext)}>
                  {activeStep.name === 'Review' ? 'Finish' : 'Next'}
                </Button>
                <Button variant="secondary" onClick={() => this.getPreviousStep(activeStep, onBack)} className={activeStep.name === 'Get Started' ? 'pf-m-disabled' : ''}>
                  Back
                </Button>
                <Button variant="link" onClick={onClose}>
                  Cancel
                </Button>
              </>
            )}}
        </WizardContextConsumer>
      </WizardFooter>
    );
    const title = 'Progressive wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        onClose={this.closeWizard}
        footer={CustomFooter}
        onGoToStep={this.onGoToStep}
        steps={steps}
        height={400}
      />
    );
  }
}
```

### Remember last step
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';

class RememberLastStepWizard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      step: 1
    };
    this.closeWizard = () => {
      console.log("close wizard");
    }
    this.onMove = (curr, prev) => {
      this.setState({
        step: curr.id
      });
    }
    this.onSave = () => {
      this.setState({
        step: 1,
      })
    }
  }

  render() {
    const { step } = this.state;

    const steps = [
      { id: 1, name: 'First step', component: <p>Step 1 content</p> },
      { id: 2, name: 'Second step', component: <p>Step 2 content</p> },
      { id: 3, name: 'Third step', component: <p>Step 3 content</p> },
      { id: 4, name: 'Fourth step', component: <p>Step 4 content</p> },
      { id: 5, name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
    ];
    const title = 'Remember last step wizard';
    return (
      <Wizard
        navAriaLabel={`${title} steps`}
        mainAriaLabel={`${title} content`}
        startAtStep={step}
        onNext={this.onMove}
        onBack={this.onMove}
        onSave={this.onSave}
        onClose={this.closeWizard}
        description="Simple Wizard Description"
        steps={steps}
        height={400}
      />
    );
  }
}
```
### Wizard in modal
```js
import React from 'react';
import { Button, Wizard } from '@patternfly/react-core';

class WizardInModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isOpen: false
    };
    this.handleModalToggle = () => {
      this.setState(({ isOpen }) => ({
        isOpen: !isOpen
      }));
    };
  }

  render() {
    const { isOpen } = this.state;

    const steps = [
      { name: 'First step', component: <p>Step 1 content</p> },
      { name: 'Second step', component: <p>Step 2 content</p> },
      { name: 'Third step', component: <p>Step 3 content</p> },
      { name: 'Fourth step', component: <p>Step 4 content</p> },
      { name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
    ];
    const title = 'Wizard in modal';
    return (
      <React.Fragment>
        <Button variant="primary" onClick={this.handleModalToggle}>
          Show Modal
        </Button>
        <Wizard
          title={title}
          description="Simple Wizard Description"
          steps={steps}
          onClose={this.handleModalToggle}
          isOpen={isOpen}
        />
      </React.Fragment>
    );
  }
}
```

