FAQAccordion
faqaccordion-1779379671446.tsx
'use client'
import { useState } from 'react'
const FAQS = [
{ id: 1, q: 'How many components are in Empire UI?', a: 'Empire UI currently has 120+ published components, with new ones added daily. Our roadmap targets 17,500 components across 30+ categories.', cat: 'General' },
{ id: 2, q: 'What frameworks does Empire UI support?', a: 'All components are built with React 18 + TypeScript. Tailwind CSS v4 is used where styling is needed. Next.js App Router compatible. Vue and Svelte variants are planned for Phase 4.', cat: 'Technical' },
{ id: 3, q: 'How does the MCP integration work?', a: 'Add empire-ui-mcp to your Claude Code or Cursor config. Then ask Claude to "find a button with a glow effect" and it will return working TSX code instantly. No copy-pasting from websites.', cat: 'MCP' },
{ id: 4, q: 'Can I use Empire UI components in commercial projects?', a: 'Yes! All plans include commercial usage rights. Free plan components are MIT licensed. Pro components include a commercial license covering unlimited projects.', cat: 'Licensing' },
{ id: 5, q: 'Is there a free tier?', a: 'Yes. The free tier gives you access to 50 components per month via the web catalogue. Pro plan removes all limits and adds MCP access, API key, and priority support.', cat: 'Pricing' },
{ id: 6, q: 'How is the quality of AI-generated components?', a: 'Every component is reviewed for TypeScript correctness, accessibility, and visual quality before publishing. Components that score below 80/100 are automatically rejected. Our average quality score is 95/100.', cat: 'Quality' },
{ id: 7, q: 'Can I request specific components?', a: 'Pro users can submit component requests. We prioritize based on vote count and implement the top requests each week.', cat: 'General' },
{ id: 8, q: 'What is the Lifetime plan?', a: 'A one-time payment of $399 gives you lifetime access to all current and future components. Limited to 1,000 spots. Once sold out, it will not be offered again.', cat: 'Pricing' },
]
export default function FAQAccordion() {
const [open, setOpen] = useState<number | null>(1)
const [search, setSearch] = useState('')
const [cat, setCat] = useState('All')
const cats = ['All', ...Array.from(new Set(FAQS.map(f => f.cat)))]
const filtered = FAQS.filter(f =>
(cat === 'All' || f.cat === cat) &&
(search === '' || f.q.toLowerCase().includes(search.toLowerCase()) || f.a.toLowerCase().includes(search.toLowerCase()))
)
return (
<div style={{ background: '#0A0A0A', padding: 32, maxWidth: 600, margin: '0 auto' }}>
<div style={{ color: '#F5F5F0', fontSize: 22, fontWeight: 800, marginBottom: 4 }}>Frequently Asked Questions</div>
<div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 14, marginBottom: 24 }}>Everything you need to know about Empire UI</div>
<input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search questions..."
style={{ width: '100%', boxSizing: 'border-box', background: 'rgba(255,255,255,0.04)', border: '1.5px solid rgba(255,255,255,0.1)', borderRadius: 10, color: '#F5F5F0', padding: '11px 16px', fontSize: 14, outline: 'none', marginBottom: 16 }} />
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 20 }}>
{cats.map(c => (
<button key={c} onClick={() => setCat(c)} style={{ background: cat === c ? 'rgba(201,168,76,0.12)' : 'rgba(255,255,255,0.04)', border: '1px solid', borderColor: cat === c ? 'rgba(201,168,76,0.3)' : 'rgba(255,255,255,0.08)', color: cat === c ? '#C9A84C' : 'rgba(255,255,255,0.4)', borderRadius: 20, padding: '4px 12px', cursor: 'pointer', fontSize: 12 }}>{c}</button>
))}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
{filtered.length === 0 && <div style={{ color: 'rgba(255,255,255,0.3)', textAlign: 'center', padding: 24, fontSize: 14 }}>No results for "{search}"</div>}
{filtered.map(faq => (
<div key={faq.id} style={{ background: '#111', border: '1px solid', borderColor: open === faq.id ? 'rgba(201,168,76,0.2)' : 'rgba(255,255,255,0.06)', borderRadius: 12, overflow: 'hidden', transition: 'border-color 0.2s' }}>
<button onClick={() => setOpen(o => o === faq.id ? null : faq.id)} style={{ width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 18px', background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left' }}>
<div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 10 }}>
<span style={{ background: 'rgba(255,255,255,0.05)', color: 'rgba(255,255,255,0.3)', padding: '1px 7px', borderRadius: 4, fontSize: 10, flexShrink: 0 }}>{faq.cat}</span>
<span style={{ color: '#F5F5F0', fontSize: 14, fontWeight: 600 }}>{faq.q}</span>
</div>
<span style={{ color: open === faq.id ? '#C9A84C' : 'rgba(255,255,255,0.25)', fontSize: 18, marginLeft: 12, flexShrink: 0, transition: 'transform 0.2s', display: 'block', transform: open === faq.id ? 'rotate(180deg)' : 'rotate(0deg)' }}>▾</span>
</button>
{open === faq.id && (
<div style={{ padding: '0 18px 16px', color: 'rgba(255,255,255,0.55)', fontSize: 14, lineHeight: 1.7, borderTop: '1px solid rgba(255,255,255,0.04)', paddingTop: 14, animation: 'fadeIn 0.2s ease' }}>
{faq.a}
</div>
)}
</div>
))}
</div>
<style>{`@keyframes fadeIn { from { opacity:0; transform:translateY(-6px) } to { opacity:1; transform:translateY(0) } }`}</style>
</div>
)
}Component info
CategoryLanding
Frameworkreact
TierFREE
Views0
Copies0
About
FAQ accordion with animated expand/collapse, search filter, and categorized questions