🎨

UI Knihovna

Kolekce nádherných, znovupoužitelných React komponent a CSS fragmentů vytvořená pomocí Tailwind CSS a Framer Motion.

Rozbalovací panely

Vertikálně skládací panely, které skrývají a odhalují obsah.

Základní panel

If you're unhappy with your purchase, we'll refund you in full.
Accordion.tsxLanguage: tsx
import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; export function BasicAccordion() { const [openIndex, setOpenIndex] = useState<number | null>(0); const items = [ { title: "What is your refund policy?", content: "If you're unhappy with your purchase, we'll refund you in full." }, { title: "Do you offer technical support?", content: "Yes, we offer 24/7 technical support for all our premium customers." }, { title: "Can I upgrade my plan later?", content: "Absolutely. You can upgrade or downgrade your plan at any time." }, ]; return ( <div className="w-full max-w-lg mx-auto bg-surface border border-border rounded-2xl overflow-hidden divide-y divide-border"> {items.map((item, index) => { const isOpen = openIndex === index; return ( <div key={index} className="overflow-hidden"> <button onClick={() => setOpenIndex(isOpen ? null : index)} className="w-full flex justify-between items-center p-5 text-left font-medium text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-colors" > {item.title} <motion.svg animate={{ rotate: isOpen ? 180 : 0 }} transition={{ duration: 0.3, ease: "easeInOut" }} className="w-5 h-5 text-muted shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2} > <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" /> </motion.svg> </button> <AnimatePresence initial={false}> {isOpen && ( <motion.div initial={{ height: 0 }} animate={{ height: "auto" }} exit={{ height: 0 }} transition={{ duration: 0.3, ease: "easeInOut" }} > <div className="p-5 pt-0 text-muted leading-relaxed"> {item.content} </div> </motion.div> )} </AnimatePresence> </div> ); })} </div> ); }