Back to library

inputs

License Key Input

Pill-shaped license key entry that morphs open on click with a spring animation. Motion-powered.

Inspired by Watermelon UI · View source

Preview

I have a License Key

Copy for AI

Copy for Lovable is the fastest way to move this component into another Lovable project — it copies the full prompt with dependencies, files, and a usage example. Copy all files gives you the raw source if you want to paste it manually.

Installation

npx shadcn@latest add https://registry.watermelon.sh/r/license-key.json

Paste into a terminal — or paste into a Lovable chat and I'll run it for you.

Source files

components/ui/license-key.tsx
import { AnimatePresence, motion, MotionConfig } from 'motion/react';
import { useState } from 'react';

const springConfig = {
  type: 'spring',
  visualDuration: 0.35,
  bounce: 0.3,
} as const;

export default function LicenceKey() {
  const [isOpen, setIsOpen] = useState(false);
  const [value, setValue] = useState('');

  const PLACEHOLDER_TEXT = 'License Key';

  return (
    <MotionConfig transition={springConfig}>
      <div className="flex h-screen w-full items-center justify-center">
        <motion.div
          className="relative h-16 cursor-pointer rounded-full bg-zinc-100 text-lg dark:bg-zinc-900 dark:text-white dark:ring-1 dark:ring-zinc-800"
          animate={{ width: isOpen ? '400px' : '230px' }}
          onClick={() => {
            if (!isOpen) {
              setIsOpen(true);
            }
          }}
        >
          <div className="flex h-full w-full items-center justify-center gap-1 pr-3 pl-4 font-semibold overflow-hidden relative">
            <AnimatePresence mode="popLayout">
              {!isOpen && (
                <motion.span
                  key="close"
                  initial={{ opacity: 0, filter: 'blur(4px)' }}
                  animate={{
                    opacity: 1,
                    filter: 'blur(0px)',
                    transition: {
                      type: 'spring',
                      visualDuration: 0.2,
                      bounce: 0,
                      delay: 0.05,
                    },
                  }}
                  exit={{ opacity: 0, filter: 'blur(4px)' }}
                  transition={{
                    type: 'spring',
                    visualDuration: 0.2,
                    bounce: 0,
                  }}
                >
                  I have a{' '}
                </motion.span>
              )}
            </AnimatePresence>

            {!isOpen && (
              <motion.span layoutId="placeholder">
                {PLACEHOLDER_TEXT}
              </motion.span>
            )}

            <AnimatePresence mode="popLayout" anchorX="right">
              {isOpen && (
                <div
                  key="open"
                  className="flex flex-1 items-center justify-start"
                >
                  <motion.span
                    layoutId="placeholder"
                    className="pointer-events-none absolute text-lg font-medium text-zinc-400 dark:text-zinc-500"
                    initial={{ opacity: 0 }}
                    animate={{
                      opacity: value.length === 0 ? 1 : 0,
                    }}
                    exit={{
                      opacity: 0,
                      filter: 'blur(4px)',
                    }}
                    transition={{
                      type: 'spring',
                      visualDuration: 0.25,
                      bounce: 0.1,
                    }}
                  >
                    {PLACEHOLDER_TEXT}
                  </motion.span>

                  <motion.input
                    autoFocus
                    initial={{
                      opacity: 0,
                      width: 0,
                    }}
                    animate={{
                      opacity: 1,
                      width: 'auto',
                    }}
                    exit={{
                      opacity: 0,
                        width: 0,
                      filter:"blur(4px)"
                    }}
                    value={value}
                    onChange={(e) => setValue(e.target.value)}
                    className="flex-1 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
                  />

                  <motion.button
                    initial={{ opacity: 0, filter: 'blur(2px)' }}
                    animate={{ opacity: 1, filter: 'blur(0px)' }}
                    exit={{ opacity: 0, filter: 'blur(2px)' }}
                    transition={{
                      type: 'spring',
                      duration: 0.3,
                      bounce: 0.1,
                    }}
                    className="cursor-pointer rounded-full bg-zinc-800 px-4 py-2 text-white ring-1 ring-zinc-800 dark:bg-white dark:text-zinc-900 dark:ring-white"
                    onClick={() => setIsOpen(false)}
                  >
                    Activate
                  </motion.button>
                </div>
              )}
            </AnimatePresence>
          </div>
        </motion.div>
      </div>
    </MotionConfig>
  );
}

Dependencies

motion