Skip to main content
Docs

Warning

This feature is deprecated. With the release of Clerk Core 3, the redesigned hooks are the recommended replacement for building custom flows. They expose stateful objects, step methods that map directly to the flow, and structured field-level errors out of the box, so you no longer need to manage attempt status, loading states, or error parsing yourself.

OTP Input

The following example demonstrates how to use the otp input type with the render prop to create a custom input field for phone and email codes, that is animated with Framer Motion.

OTP Input
<Clerk.Input
  type="otp"
  required
  className="flex justify-center gap-1"
  render={({ value, status }) => (
    <div
      data-status={status}
      className="relative h-9 w-8 rounded-md bg-white ring-1 ring-inset ring-zinc-300 data-[status=selected]:bg-sky-400/10 data-[status=selected]:shadow-[0_0_8px_2px_theme(colors.sky.400/30%)] data-[status=selected]:ring-sky-400"
    >
      <AnimatePresence>
        {value && (
          <motion.span
            initial={{ opacity: 0, scale: 0.75 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.75 }}
            className="absolute inset-0 flex items-center justify-center text-zinc-950"
          >
            {value}
          </motion.span>
        )}
        {value}
      </AnimatePresence>
      {status === 'cursor' && (
        <motion.div
          layoutId="otp-input-focus"
          transition={{ ease: [0.2, 0.4, 0, 1], duration: 0.2 }}
          className="absolute inset-0 z-10 rounded-[inherit] border border-sky-400 bg-sky-400/10 shadow-[0_0_8px_2px_theme(colors.sky.400/30%)]"
        />
      )}
    </div>
  )}
/>

Feedback

What did you think of this content?

Last updated on