Docs
Go back
Component by
OV
OblivionAbsolutely. Oblivion is completely open-source and free to use for any personal or commercial application. You don't even need to provide attribution.
TSX
liquid-faqs
"use client"
import React, { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import { Plus } from "lucide-react"
import { cn } from "@/lib/utils"
export const componentMeta = {
name: "Liquid FAQs",
description: "A physics-based, fluid accordion component perfect for majestic FAQ sections, built with Framer Motion layout animations.",
props: {
title: { type: "string", description: "The title of the FAQ section", default: '"Frequently Asked Questions"' },
description: { type: "string", description: "The subtitle", default: '"Everything you need to know about the product."' },
items: { type: "array", description: "Array of FAQ items", default: "[]" }
}
}
interface AccordionItem {
question: string
answer: string
}
function AccordionItemComponent({ item, isOpen, onClick }: { item: AccordionItem, isOpen: boolean, onClick: () => void }) {
return (
<div className="border border-black/5 dark:border-white/5 bg-white dark:bg-zinc-900 overflow-hidden rounded-2xl mb-3 transition-colors hover:bg-neutral-50 dark:hover:bg-zinc-800/50">
<button
type="button"
onClick={onClick}
className="flex w-full items-center justify-between px-6 py-5 text-left focus:outline-none"
>
<span className="font-semibold text-neutral-900 dark:text-neutral-100">{item.question}</span>
<motion.div
animate={{ rotate: isOpen ? 45 : 0 }}
transition={{ duration: 0.3, ease: [0.32, 0.72, 0, 1] }}
className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 dark:bg-zinc-800 flex-shrink-0"
>
<Plus className="h-4 w-4 text-neutral-500 dark:text-neutral-400" />
</motion.div>
</button>
<AnimatePresence initial={false}>
{isOpen && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.4, ease: [0.32, 0.72, 0, 1] }}
>
<div className="px-6 pb-6 pt-0 text-neutral-500 dark:text-neutral-400 leading-relaxed">
{item.answer}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
)
}
export default function FAQComponent({
title = "Frequently Asked Questions",
description = "Find answers to everything you need to know about setting up and using Oblivion UI.",
items = [
{ question: "Can I use Oblivion for commercial projects?", answer: "Absolutely. Oblivion is completely open-source and free to use for any personal or commercial application. You don't even need to provide attribution." },
{ question: "How does this compare to Shadcn UI?", answer: "Shadcn UI provides fundamental building blocks (like Buttons, Inputs, Dialogs). Oblivion UI provides complex, highly animated, pre-composed sections (like Hero Sections, Advanced Pricing Tables, Marquees) built on top of those fundamentals using Framer Motion." },
{ question: "Do I actually just copy and paste the code?", answer: "Yes! There are no hidden npm packages for components. You literally hit 'Copy Code', paste it into your components directory, and you have complete ownership to edit and modify it however you want." },
{ question: "What animations library do you use?", answer: "We exclusively use Framer Motion for React. It is the gold standard for physics-based layout animations, ensuring every spring feels perfectly damped and butter-smooth." }
]
}: {
title?: string
description?: string
items?: AccordionItem[]
}) {
const [openIndex, setOpenIndex] = useState<number | null>(0)
return (
<div className="w-full max-w-2xl mx-auto py-12">
<div className="w-full">
{items.map((item, index) => (
<AccordionItemComponent
key={index}
item={item}
isOpen={openIndex === index}
onClick={() => setOpenIndex(openIndex === index ? null : index)}
/>
))}
</div>
</div>
)
}"use client"
import React, { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import { Plus } from "lucide-react"
import { cn } from "@/lib/utils"
export const componentMeta = {
name: "Liquid FAQs",
description: "A physics-based, fluid accordion component perfect for majestic FAQ sections, built with Framer Motion layout animations.",
props: {
title: { type: "string", description: "The title of the FAQ section", default: '"Frequently Asked Questions"' },
description: { type: "string", description: "The subtitle", default: '"Everything you need to know about the product."' },
items: { type: "array", description: "Array of FAQ items", default: "[]" }
}
}
interface AccordionItem {
question: string
answer: string
}
function AccordionItemComponent({ item, isOpen, onClick }: { item: AccordionItem, isOpen: boolean, onClick: () => void }) {
return (
<div className="border border-black/5 dark:border-white/5 bg-white dark:bg-zinc-900 overflow-hidden rounded-2xl mb-3 transition-colors hover:bg-neutral-50 dark:hover:bg-zinc-800/50">
<button
type="button"
onClick={onClick}
className="flex w-full items-center justify-between px-6 py-5 text-left focus:outline-none"
>
<span className="font-semibold text-neutral-900 dark:text-neutral-100">{item.question}</span>
<motion.div
animate={{ rotate: isOpen ? 45 : 0 }}
transition={{ duration: 0.3, ease: [0.32, 0.72, 0, 1] }}
className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 dark:bg-zinc-800 flex-shrink-0"
>
<Plus className="h-4 w-4 text-neutral-500 dark:text-neutral-400" />
</motion.div>
</button>
<AnimatePresence initial={false}>
{isOpen && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.4, ease: [0.32, 0.72, 0, 1] }}
>
<div className="px-6 pb-6 pt-0 text-neutral-500 dark:text-neutral-400 leading-relaxed">
{item.answer}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
)
}
export default function FAQComponent({
title = "Frequently Asked Questions",
description = "Find answers to everything you need to know about setting up and using Oblivion UI.",
items = [
{ question: "Can I use Oblivion for commercial projects?", answer: "Absolutely. Oblivion is completely open-source and free to use for any personal or commercial application. You don't even need to provide attribution." },
{ question: "How does this compare to Shadcn UI?", answer: "Shadcn UI provides fundamental building blocks (like Buttons, Inputs, Dialogs). Oblivion UI provides complex, highly animated, pre-composed sections (like Hero Sections, Advanced Pricing Tables, Marquees) built on top of those fundamentals using Framer Motion." },
{ question: "Do I actually just copy and paste the code?", answer: "Yes! There are no hidden npm packages for components. You literally hit 'Copy Code', paste it into your components directory, and you have complete ownership to edit and modify it however you want." },
{ question: "What animations library do you use?", answer: "We exclusively use Framer Motion for React. It is the gold standard for physics-based layout animations, ensuring every spring feels perfectly damped and butter-smooth." }
]
}: {
title?: string
description?: string
items?: AccordionItem[]
}) {
const [openIndex, setOpenIndex] = useState<number | null>(0)
return (
<div className="w-full max-w-2xl mx-auto py-12">
<div className="w-full">
{items.map((item, index) => (
<AccordionItemComponent
key={index}
item={item}
isOpen={openIndex === index}
onClick={() => setOpenIndex(openIndex === index ? null : index)}
/>
))}
</div>
</div>
)
}Save to favoritesCopy to Figma
React
Liquid FAQs
A physics-based, fluid accordion component perfect for majestic FAQ sections, built with Framer Motion layout animations.
Installation
$ npx @cosmoo/oblivion add liquid-faqsDependencies
npm install framer-motion lucide-reactUsage Example
tsx
import LiquidFaqs from "@/components/oblivion/liquid-faqs"
export default function Demo() {
return (
<div className="p-10 flex justify-center">
<LiquidFaqs />
</div>
)
}import LiquidFaqs from "@/components/oblivion/liquid-faqs"
export default function Demo() {
return (
<div className="p-10 flex justify-center">
<LiquidFaqs />
</div>
)
}