Spotlight

A RhSpotlight helps new users get familiar with the product's features easily, so they can start using it without any confusion.

To create a spotlight in your web app, you need to use RhSpotlightManager as a parent component and RhSpotlightStep as children. The card component should be wrapped in RhSpotlightStep, which allows you to display one card at a time and also Pass a pulse boolean value to control whether the animation should be applied around the view or the icon.

Usage

Once installed, you can import the RhSpotlight component into your React application:

copy
import {RhSpotlight, RhSpotlightManager, RhSpotlightStep} from "@rhythm-ui/react"

Then, you can use the RhSpotlight component in your JSX code:

copy
function SpotLightComponent() {
  const [dismiss, setDismiss] = useState(true); //If dismiss is true then the spotlight will stop
  const [currentStep, setCurrentStep] = useState(0); //state for managing which card should be shown at a time
  const [showSpotlight, setShowSpotlight] = useState(true); //control the trigger of spotlight from here.
  const totalTour = 4;
  const handleActiveStep = (num) => {
    setCurrentStep(num);
  };
  const dismissHandler = (bool) => {
    setDismiss(bool);
  };

  const FirstCard = ({
    handleActiveStep,
    dismissHandler,
    totalTour,
    order,
  }) => {
    return (
      <RhCard className="p-2 mt-2 w-80">
        <div className="flex flex-col">
          <p className="text-xs text-justify">
            A database is an organized collection of structured information
          </p>
          <div className="flex justify-between items-center">
            <span className="text-xs">{`${order + 1}/${totalTour}`}</span>
            <div className="flex gap-3">
              <RhButton
                size="xs"
                variant="secondary"
                layout="link"
                onClick={() => dismissHandler(true)}
              >
                Dismiss
              </RhButton>
              <RhButton size="xs" onClick={() => handleActiveStep(1)}>
                Next
              </RhButton>
            </div>
          </div>
        </div>
      </RhCard>
    );
  };

  const SecondCard = ({ handleActiveStep, totalTour, order }) => {
    return (
      <RhCard className="p-2 mt-2 w-80">
        <div className="flex flex-col gap-5">
          <p className="text-xs text-justify">
            This allows users to copy or cut information from the clipboard
          </p>
          <div className="flex justify-between items-center">
            <span className="text-xs">{`${order + 1}/${totalTour}`}</span>
            <div className="flex ml-2 gap-3">
              <RhButton
                size="xs"
                variant="secondary"
                layout="link"
                onClick={() => dismissHandler(true)}
              >
                Dismiss
              </RhButton>
              <RhButton
                size="xs"
                variant="secondary"
                layout="outline"
                onClick={() => handleActiveStep(0)}
              >
                Back
              </RhButton>
              <RhButton size="xs" onClick={() => handleActiveStep(2)}>
                Next
              </RhButton>
            </div>
          </div>
        </div>
      </RhCard>
    );
  };

  const ThirdCard = ({ handleActiveStep, totalTour, order }) => {
    return (
      <RhCard className="p-2 mt-2 w-80">
        <div className="flex flex-col gap-5">
          <p className="text-xs text-justify">
            The purpose of a user tour is to help new users get up to speed
            quickly and become familiar with the product.
          </p>
          <div className="flex justify-between items-center">
            <span className="text-xs">{`${order + 1}/${totalTour}`}</span>
            <div className="flex ml-2 gap-3">
              <RhButton
                size="xs"
                variant="secondary"
                layout="link"
                onClick={() => dismissHandler(true)}
              >
                Dismiss
              </RhButton>
              <RhButton
                size="xs"
                variant="secondary"
                layout="outline"
                onClick={() => handleActiveStep(1)}
              >
                Back
              </RhButton>
              <RhButton size="xs" onClick={() => handleActiveStep(3)}>
                Next
              </RhButton>
            </div>
          </div>
        </div>
      </RhCard>
    );
  };

  const FourthCard = ({ handleActiveStep, totalTour, order }) => {
    return (
      <RhCard className="p-2 mt-2 w-80">
        <div className="flex flex-col gap-5">
          <p className="text-xs text-justify">
            this allows the user to exit the guided tour
          </p>
          <div className="flex justify-between items-center">
            <span className="text-xs">{`${order + 1}/${totalTour}`}</span>
            <div className="flex ml-2 gap-3">
              <RhButton
                size="xs"
                variant="secondary"
                layout="outline"
                onClick={() => handleActiveStep(3)}
              >
                Back
              </RhButton>
              <RhButton size="xs" onClick={() => dismissHandler(true)}>
                Ok
              </RhButton>
            </div>
          </div>
        </div>
      </RhCard>
    );
  };

  const FifthCard = ({
    handleActiveStep,
    dismissHandler,
    totalTour,
    order,
  }) => {
    return (
      <RhCard className="p-2 mt-2 w-80">
        <div className="flex flex-col gap-5">
          <p className="text-xs text-justify">
            this allows the user to exit the guided tour
          </p>
          <div className="flex justify-between items-center">
            <span className="text-xs">{`${order + 1}/${totalTour}`}</span>
            <div className="flex ml-2 gap-3">
              <RhButton
                size="xs"
                variant="secondary"
                layout="outline"
                onClick={() => handleActiveStep(2)}
              >
                Back
              </RhButton>
              <RhButton
                size="xs"
                variant="primary"
                onClick={() => handleActiveStep(4)}
              >
                Next
              </RhButton>
            </div>
          </div>
        </div>
      </RhCard>
    );
  };

  return (
    <div className="p-4">
      <RhSpotlightManager
        activeStep={currentStep}
        dismiss={dismiss}
        triggerStart={showSpotlight}
      >
        <div className="flex flex-col justify-center items-center gap-20">
          <div className="w-full flex items-center justify-center gap-7">
            <RhSpotlightStep
              customComponent={
                <FirstCard
                  dismissHandler={dismissHandler}
                  handleActiveStep={handleActiveStep}
                  totalTour={totalTour}
                  order={0}
                />
              }
              order={0}
              totalTour={totalTour}
              pulse={true}
            >
              <RhIcon
                icon="heroicons:circle-stack-solid"
                className="text-3xl text-gray-400"
              />
            </RhSpotlightStep>

            <RhSpotlightStep
              customComponent={
                <SecondCard
                  dismissHandler={dismissHandler}
                  handleActiveStep={handleActiveStep}
                  totalTour={totalTour}
                  order={1}
                />
              }
              order={1}
              totalTour={totalTour}
              pulse={false}
            >
              <RhIcon
                icon="heroicons:clipboard-document-solid"
                className="text-3xl text-gray-400"
              />
            </RhSpotlightStep>

            <RhSpotlightStep
              customComponent={
                <ThirdCard
                  dismissHandler={dismissHandler}
                  handleActiveStep={handleActiveStep}
                  totalTour={totalTour}
                  order={2}
                />
              }
              order={2}
              totalTour={totalTour}
              pulse={false}
            >
              <RhButton variant="primary" size="xs">
                User Tour
              </RhButton>
            </RhSpotlightStep>

            <RhSpotlightStep
              customComponent={
                <FourthCard
                  dismissHandler={dismissHandler}
                  handleActiveStep={handleActiveStep}
                  totalTour={totalTour}
                  order={3}
                />
              }
              order={3}
              totalTour={totalTour}
              pulse={false}
            >
              <RhButton variant="secondary" layout="outline" size="xs">
                Finish
              </RhButton>
            </RhSpotlightStep>
          </div>
          <RhButton
            onClick={() => {
              setDismiss(false);
              setCurrentStep(0);
            }}
          >
            Click to start tour
          </RhButton>
        </div>
      </RhSpotlightManager>
    </div>
  );
}

Spotlight Manager PropsTable

triggerStartbooleanTakes in a boolean value (true/false) from a parent. Used to start the spotlight
activeStepnumberSent by a parent. Takes in a number and is used by setCurrentStepIndex to set the latest index
dismissbooleanDismisses the spotlight

Spotlight step PropsTable

childrenReact.ReactElementjsx element
ordernumberTakes a number value. Used to determine the next step
customComponentanypass any custom component
pulsebooleantruePass a boolean value to control whether the animation should be applied around the view or the icon.
animationClassNamestringPass custom style for pulse animation