← Components/Landing

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

More from Landing

'use client'
import { useState } from 'react'

const PLANS = [
  {
    name: 'Free', monthly: 0, annual: 0, color: '#64748b', highlight: false,
    features: ['50 components/month', 'Basic search', 'React + TSX', 'Community support', null, null],
  }
PricingCards
Landing