Oblivion
Oblivion
Docs
Go back
Component by
OV
Oblivion
Absolutely. 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>
  )
}
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-faqs
Dependenciesnpm install framer-motion lucide-react

Usage Example

tsx
import LiquidFaqs from "@/components/oblivion/liquid-faqs"

export default function Demo() {
  return (
    <div className="p-10 flex justify-center">
      <LiquidFaqs />
    </div>
  )
}