FAQ
Fri Sep 12 2025
Frequently Asked Questions accordion component with collapsible sections for organizing help content and common inquiries
FAQ Section
An accordion-style FAQ component for organizing frequently asked questions.
Usage
Coming soon - this component is under development.
FAQ Contact Card
交互式的 FAQ 组件,包含联系信息卡片和可展开的问答列表,适用于客户支持页面。
"use client";import { FAQContactCard, type FAQContactCardData } from "./faq-contact-card";const sampleFAQData: FAQContactCardData = { contact: { title: "Still have questions?", description: "Can't find the answer you're looking for? Please chat to our support.", avatarImage: "/avator/sawana-huang-212x212.webp", button: "Get In Touch", buttonHref: "/contact", emailHref: "mailto:[email protected]", githubHref: "https://github.com/example/support", }, faqs: [ { question: "What is this product?", answer: "This is a sample product description that explains the main features and benefits of our service.", }, { question: "How do I get started?", answer: "Getting started is simple. Just sign up for an account and follow our quick setup guide.", }, { question: "Is there a free plan?", answer: "Yes, we offer a free tier with basic features to help you get started.", }, { question: "How can I contact support?", answer: "You can reach our support team through email, GitHub, or by using the contact button above.", }, ],};export function FAQContactCardDemo() { return ( <div className="min-h-[600px] w-full"> <FAQContactCard data={sampleFAQData} /> </div> );}功能特点
- shadcn/ui 设计: 基于 Card 和 Accordion 组件构建,保持设计系统一致性
- 响应式布局: 移动端垂直布局,桌面端双栏布局
- 原生 Accordion: 使用 shadcn Accordion 组件,支持键盘导航和动画
- 联系信息卡片: 结构化 Card 布局,包含头像、标题、描述和操作区域
- 社交媒体链接: 可配置的邮件和 GitHub 链接支持
- 完全可配置: 所有文本内容和链接均通过 props 传入
- 主题兼容: 支持 Light/Dark 模式切换
Code
"use client";
import React from "react";
import { Button } from "@/components/ui/button";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/ui/accordion";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { Mail, Github } from "lucide-react";
interface FAQItem {
question: string;
answer: string;
}
interface ContactInfo {
title: string;
description: string;
avatarImage: string;
button: string;
buttonHref: string;
emailHref: string;
githubHref: string;
}
interface FAQContactCardData {
contact: ContactInfo;
faqs: FAQItem[];
}
interface FAQContactCardProps {
data: FAQContactCardData;
className?: string;
}
export function FAQContactCard({ data, className }: FAQContactCardProps) {
return (
<div
className={cn(
"flex flex-col items-start lg:flex-row lg:space-x-6",
className,
)}
>
{/* Contact Card */}
<div className="w-full flex-none lg:flex-[1_1_500px]">
<Card className="mb-6 h-full">
<CardHeader>
<div className="flex flex-row gap-4">
<img
src={data.contact.avatarImage}
alt="Contact Avatar"
className="inline-block h-12 w-12 rounded-full object-cover"
loading="lazy"
/>
<div className="flex flex-col gap-1.5">
<CardTitle className="text-xl">{data.contact.title}</CardTitle>
<CardDescription className="max-w-sm">
{data.contact.description}
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center space-x-4">
<Link
href={data.contact.emailHref}
aria-label="Email Support"
target="_blank"
>
<div className="bg-primary/10 hover:bg-primary/20 flex h-10 w-10 items-center justify-center rounded-full transition-colors">
<Mail className="text-primary h-5 w-5" />
</div>
</Link>
<Link
href={data.contact.githubHref}
target="_blank"
aria-label="GitHub Support"
>
<div className="bg-primary/10 hover:bg-primary/20 flex h-10 w-10 items-center justify-center rounded-full transition-colors">
<Github className="text-primary h-5 w-5" />
</div>
</Link>
</div>
</CardContent>
<CardFooter>
<Link href={data.contact.buttonHref}>
<Button className="w-full">{data.contact.button}</Button>
</Link>
</CardFooter>
</Card>
</div>
{/* FAQ Cards with Accordion */}
<div className="w-full flex-none lg:flex-[1_1_500px]">
<Accordion type="single" collapsible className="w-full space-y-4">
{data.faqs.map((faq, index) => (
<AccordionItem
key={index}
value={`item-${index}`}
className="border-0"
>
<Card>
<CardHeader className="pb-3">
<AccordionTrigger className="p-0 text-left hover:no-underline [&[data-state=open]>svg]:rotate-180">
<CardTitle className="text-base font-semibold">
{faq.question}
</CardTitle>
</AccordionTrigger>
</CardHeader>
<AccordionContent className="pt-0">
<CardContent className="pt-0">
<p className="text-muted-foreground text-sm leading-relaxed">
{faq.answer}
</p>
</CardContent>
</AccordionContent>
</Card>
</AccordionItem>
))}
</Accordion>
</div>
</div>
);
}
export type { FAQContactCardData, FAQItem, ContactInfo };