Skip to content

Demos

Basic usage

Heading

Contents

Contents

Code Editor
const initialData = {
  firstName: 'John',
  lastName: 'Doe',
  streetName: 'Osloveien',
  streetNr: 12,
  postalCode: '1234',
  city: 'Oslo',
}
const Step1 = () => (
  <Wizard.Step title="Step 1">
    <Form.MainHeading>Heading</Form.MainHeading>
    <Form.Card>
      <P>Contents</P>
    </Form.Card>
    <Form.Card>
      <P>Contents</P>
    </Form.Card>

    <Wizard.Buttons />
  </Wizard.Step>
)
const Step2 = () => (
  <Wizard.Step title="Step 2">
    <Form.MainHeading>Heading</Form.MainHeading>
    <Form.Card>
      <P>Contents</P>
    </Form.Card>
    <Form.Card>
      <P>Contents</P>
    </Form.Card>

    <Wizard.Buttons />
  </Wizard.Step>
)
const Summary = () => {
  const { summaryTitle } = Form.useTranslation().Step
  return (
    <Wizard.Step title={summaryTitle}>
      <Form.MainHeading>Summary</Form.MainHeading>
      <Form.Card>
        <Form.SubHeading>Deliver address</Form.SubHeading>

        <Value.SummaryList layout="grid">
          <Value.Name.First path="/firstName" />
          <Value.Name.Last path="/lastName" />

          <Value.Composition label="Street">
            <Value.String path="/streetName" />
            <Value.Number path="/streetNr" />
          </Value.Composition>

          <Value.Composition label="City">
            <Value.String path="/postalCode" />
            <Value.String path="/city" />
          </Value.Composition>
        </Value.SummaryList>

        <Wizard.EditButton toStep={1} />
      </Form.Card>

      <Form.ButtonRow>
        <Wizard.Buttons />
        <Form.SubmitButton variant="send" />
      </Form.ButtonRow>
    </Wizard.Step>
  )
}

// Can be an async function, in case you need to make some async stuff
const onStepChange = async (step, mode) => {
  if (mode === 'next') {
    await new Promise((resolve) => setTimeout(resolve, 1000))
  }
  console.log('onStepChange', step, mode)
}

// Can be an async function, in case you need to make some async stuff
const onSubmit = async (data) => {
  await new Promise((resolve) => setTimeout(resolve, 2000))
  console.log('onSubmit', data)
}
const MyForm = () => {
  // Routers like "react-router" are supported as well
  Wizard.useQueryLocator('my-wizard')
  return (
    <Form.Handler data={initialData} onSubmit={onSubmit}>
      <Wizard.Container id="my-wizard" onStepChange={onStepChange}>
        <Step1 />
        <Step2 />
        <Summary />
      </Wizard.Container>
    </Form.Handler>
  )
}
render(<MyForm />)

Async wizard

Code Editor
const MyForm = () => {
  const onStepChange = React.useCallback(async (index, mode) => {
    console.log('onStepChange', index)
    if (mode === 'next') {
      try {
        const request = createRequest()
        await request(1000) // Simulate a request
      } catch (error) {
        return error
      }
    }

    // Optional, you can show a FormStatus at the bottom of the form
    return {
      info: `Info message: ${index}`,
    }
  }, [])
  const onSubmit = React.useCallback(async (data) => {
    console.log('onSubmit', data)
    try {
      const request = createRequest()
      await request(1000) // Simulate a request
    } catch (error) {
      return error
    }

    // Optional, you can show a FormStatus at the bottom of the form
    return {
      warning: 'Warning message',
    }
  }, [])
  const validator = React.useCallback(async (value) => {
    try {
      const request = createRequest()
      await request(1000) // Simulate a request
    } catch (error) {
      return error
    }
    if (value === 'invalid') {
      return Error('Error message')
    }
  }, [])
  const validator1 = debounceAsync(validator)
  const validator2 = debounceAsync(validator)
  const Step1 = () => {
    return (
      <Wizard.Step title="Step 1">
        <Form.Card>
          <Field.String
            label="Required field with async validator"
            onChangeValidator={validator1}
            path="/field1"
            required
          />
          <Field.String
            label="Field with async validator"
            onChangeValidator={validator2}
            path="/field2"
          />
        </Form.Card>

        <Wizard.Buttons />
      </Wizard.Step>
    )
  }
  const Step2 = () => {
    return (
      <Wizard.Step title="Step 2">
        <Form.MainHeading>Heading</Form.MainHeading>

        <Form.Card>
          <P>Contents of step 2</P>
        </Form.Card>

        <Form.ButtonRow>
          <Wizard.Buttons />
          <Form.SubmitButton variant="send" />
        </Form.ButtonRow>
      </Wizard.Step>
    )
  }
  return (
    <Form.Handler onSubmit={onSubmit}>
      <Wizard.Container onStepChange={onStepChange}>
        <Step1 />
        <Step2 />
      </Wizard.Container>
    </Form.Handler>
  )
}
render(<MyForm />)

With StatusMessage in Menu

This example uses the loose mode to demonstrate status messages. Press the Send button to see the status message. You may also navigate to the previous steps and press the Send button again.

Code Editor
<Form.Handler
  onSubmit={(data) => {
    console.log('onSubmit', data)
  }}
>
  <Wizard.Container
    onStepChange={async (index, mode) => {
      console.log('onStepChange', index, mode)
    }}
    mode="loose"
    initialActiveIndex={2}
  >
    <Wizard.Step title="Step 1">
      <Field.String label="Step 1" path="/step1" required />
      <Wizard.Buttons />
    </Wizard.Step>

    <Wizard.Step title="Step 2">
      <Field.String label="Step 2" path="/step2" required />
      <Wizard.Buttons />
    </Wizard.Step>

    <Wizard.Step title="Step 3">
      <Field.String label="Step 3" path="/step3" />
      <Wizard.Buttons />
    </Wizard.Step>
  </Wizard.Container>

  <Form.SubmitButton />
</Form.Handler>

With StatusMessage

Step 1

Content

Code Editor
<Form.Handler>
  <Wizard.Container
    onStepChange={async (index, mode, { preventNavigation }) => {
      preventNavigation()
      return {
        info: 'Info message.',
        warning: 'Warning message.',
      }
    }}
  >
    <Wizard.Step title="Step 1">
      <Form.MainHeading>Step 1</Form.MainHeading>
      <P>Content</P>
      <Wizard.NextButton text="Press me to see the status message" />
    </Wizard.Step>
  </Wizard.Container>
</Form.Handler>

Get errors before submit or step change

You can use the onSubmitRequest property on the Form.Handler to get visible errors before the form is submitted.

Each item in the error array contains the following properties in an object:

  • path The path of the field.
  • value The value of the field.
  • displayValue The displayed value of the field.
  • label The label of the field.
  • props The given field properties.
  • error The error of the field.
const onSubmitRequest: OnSubmitRequest = ({ getErrors }) => {
getErrors().forEach(
({ path, value, displayValue, label, props, error }) => {
// Do something with the error
console.log(label, error.message)
}
)
}
Code Editor
<Form.Handler
  onSubmitRequest={({ getErrors }) => {
    getErrors().forEach(({ label, error }) => {
      console.log(label, error.message)
    })
  }}
>
  <Wizard.Container mode="loose">
    <Wizard.Step title="Step 1">
      <Form.Card>
        <Field.String
          path="/foo"
          label="Foo"
          defaultValue="With default value"
          required
        />
        <Field.String path="/bar" label="Bar" required />
      </Form.Card>

      <Wizard.Buttons />
    </Wizard.Step>

    <Wizard.Step title="Step 2">
      <Form.Card>
        <Field.String path="/baz" label="Baz" required />
      </Form.Card>

      <Wizard.Buttons />

      <Form.SubmitButton />
    </Wizard.Step>
  </Wizard.Container>
</Form.Handler>