Docs
PopoverForm
PopoverForm
A headless popover form animation component with customizable options.
Theme
References
This component is inspired by and adapted from the open source Cult UI project. We've customized it to fit our design system while maintaining the original aesthetic and functionality.
Inspiration
Installation
Install the required dependencies.
npx shadcn@latest add "http://skiper-ui.com/registry/minimal-card.json"
Usage
import {
PopoverForm,
PopoverFormButton,
PopoverFormCutOutLeftIcon,
PopoverFormCutOutRightIcon,
PopoverFormSeparator,
PopoverFormSuccess,
} from "@/registry/default/ui/popover-form"
export default function PopoverFormFeedbackExample() {
const [formState, setFormState] = useState<FormState>("idle")
const [open, setOpen] = useState(false)
const [feedback, setFeedback] = useState("")
function submit() {
setFormState("loading")
setTimeout(() => {
setFormState("success")
}, 1500)
setTimeout(() => {
setOpen(false)
setFormState("idle")
setFeedback("")
}, 3300)
}
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setOpen(false)
}
if (
(event.ctrlKey || event.metaKey) &&
event.key === "Enter" &&
open &&
formState === "idle"
) {
submit()
}
}
window.addEventListener("keydown", handleKeyDown)
return () => window.removeEventListener("keydown", handleKeyDown)
}, [open, formState])
return (
<div className="flex w-full items-center justify-center">
<PopoverForm
title="Feedback"
open={open}
setOpen={setOpen}
width="364px"
height="192px"
showCloseButton={formState !== "success"}
showSuccess={formState === "success"}
openChild={
<form
onSubmit={(e) => {
e.preventDefault()
if (!feedback) return
submit()
}}
>
<div className="relative">
<textarea
autoFocus
placeholder="Feedback"
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
className="h-32 w-full resize-none rounded-t-lg p-3 text-sm outline-none"
required
/>
</div>
<div className="relative flex h-12 items-center px-[10px]">
<PopoverFormSeparator />
<div className="absolute left-0 top-0 -translate-x-[1.5px] -translate-y-1/2">
<PopoverFormCutOutLeftIcon />
</div>
<div className="absolute right-0 top-0 translate-x-[1.5px] -translate-y-1/2 rotate-180">
<PopoverFormCutOutRightIcon />
</div>
<PopoverFormButton loading={formState === "loading"} />
</div>
</form>
}
successChild={
<PopoverFormSuccess
title="Feedback Received"
description="Thank you for supporting our project!"
/>
}
/>
</div>
)
}