DEV Community

Gabriel Linassi
Gabriel Linassi

Posted on

How to create a Steps Wizzard in React

This is a quick tutorial to show you the barebones of how to create a Wizzard Steps component.

import type { NextPage } from 'next';
import React, { useReducer } from 'react';

type StepsProps = {
  children: React.ReactNode;
};

const Steps = ({ children }: StepsProps) => {
  let idx = 0;

  const _children = React.Children.map(children, (child) => {
    if (!React.isValidElement(child)) return null;
    return React.cloneElement(child, { ...child.props, idx: ++idx });
  });

  return <div className="space-y-1">{_children}</div>;
};

type StepProps = {
  title: string;
  children: React.ReactNode;
  idx?: number;
};

const Step = ({ title, idx, children }: StepProps) => {
  return (
    <div className="border border-dashed border-gray-400 p-2">
      <div className="flex gap-2">
        <span className="bg-red-300 px-1">{idx}</span>
        <h4>{title}</h4>
      </div>
      <div className="mt-2">{children}</div>
    </div>
  );
};

const Home: NextPage = () => {
  const [hasWarranty, toggleWarranty] = useReducer((s) => !s, false);

  return (
    <div className="p-4">
      <h1 className="text-2xl">Checkout</h1>
      <button
        onClick={toggleWarranty}
        className="bg-gray-700 px-2 py-1 text-white"
      >
        Toggle Warranty Step
      </button>
      <div className="mt-3">
<Steps>
  <Step title="Contact Details">Step Details</Step>
  <Step title="Aditional Add-Ons">Step Details</Step>
  {hasWarranty && <Step title="Extended Warranty">Step Details</Step>}
  <Step title="Shipping Details">Step Details</Step>
  <Step title="Payment Details">Step Details</Step>
</Steps>
      </div>
    </div>
  );
};

export default Home;

Enter fullscreen mode Exit fullscreen mode

Notice how the <Steps/> injects the idx into the <Step/> component without having to manually enter it.

const Steps = ({ children }: StepsProps) => {
  let idx = 0;

  const _children = React.Children.map(children, (child) => {
    if (!React.isValidElement(child)) return null;
    return React.cloneElement(child, { ...child.props, idx: ++idx });
  });

  return <div className="space-y-1">{_children}</div>;
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)