Back to Discover
FormsIntermediate
Multi-Step Form
An elegant multi-step wizard with Framer Motion slide transitions.
Live Preview
1
2
3
Personal Info
"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
export function MultiStepForm() {
const [step, setStep] = useState(1);
return (
<div className="w-full max-w-sm rounded-2xl border border-border bg-[#0a0a0a] p-8 shadow-xl">
<div className="flex justify-between mb-8">
{[1, 2, 3].map((i) => (
<div key={i} className={`flex h-8 w-8 items-center justify-center rounded-full text-xs font-medium transition-colors ${step >= i ? "bg-foreground text-background" : "bg-muted text-muted-foreground"}`}>
{i}
</div>
))}
</div>
<div className="h-40 relative">
<AnimatePresence mode="wait">
{step === 1 && (
<motion.div key="1" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} className="absolute inset-0">
<h3 className="text-lg font-medium mb-4">Personal Info</h3>
<input type="text" placeholder="Full Name" className="w-full mb-3 rounded-md border border-border bg-transparent px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-foreground" />
</motion.div>
)}
{step === 2 && (
<motion.div key="2" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} className="absolute inset-0">
<h3 className="text-lg font-medium mb-4">Security</h3>
<input type="password" placeholder="Password" className="w-full mb-3 rounded-md border border-border bg-transparent px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-foreground" />
</motion.div>
)}
{step === 3 && (
<motion.div key="3" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} className="absolute inset-0">
<h3 className="text-lg font-medium mb-4">Done!</h3>
<p className="text-sm text-muted-foreground">Your account is ready to go.</p>
</motion.div>
)}
</AnimatePresence>
</div>
<div className="flex justify-between mt-4">
<button
onClick={() => setStep(s => Math.max(1, s - 1))}
disabled={step === 1}
className="text-sm font-medium text-muted-foreground disabled:opacity-50 hover:text-foreground"
>
Back
</button>
<button
onClick={() => setStep(s => Math.min(3, s + 1))}
className="rounded-md bg-foreground text-background px-4 py-2 text-sm font-medium hover:bg-[#e0e0e0] transition-colors"
>
{step === 3 ? "Complete" : "Next"}
</button>
</div>
</div>
);
}