FAQ/

フローティングカードFAQ

Preview

カードグリッドレイアウトで質問を配置したFAQセクション。各質問が独立したカードとして表示され、クリックで回答が展開される洗練されたデザイン。

Source Code
tsx
152 lines
1"use client";
2
3import { useState } from "react";
4
5const faqItems = [
6 {
7 number: "01",
8 question: "導入までの期間はどのくらいですか?",
9 answer:
10 "標準的なプロジェクトで2〜4週間、大規模なカスタマイズが必要な場合は6〜8週間が目安です。初回のヒアリングで詳細なスケジュールをご提案いたします。",
11 },
12 {
13 number: "02",
14 question: "料金体系を教えてください。",
15 answer:
16 "月額サブスクリプション制で、チーム規模と利用機能に応じた3つのプランをご用意しています。年間契約で20%の割引が適用されます。",
17 },
18 {
19 number: "03",
20 question: "既存システムとの連携は可能ですか?",
21 answer:
22 "主要なCRM・ERP・会計ソフトとのAPI連携に対応しています。Webhookによるカスタム連携も可能です。技術的なご質問はサポートチームまでお問い合わせください。",
23 },
24 {
25 number: "04",
26 question: "セキュリティ対策について教えてください。",
27 answer:
28 "SOC 2 Type IIおよびISO 27001の認証を取得済みです。すべてのデータはAES-256で暗号化され、日次バックアップと99.9%のアップタイム保証を提供しています。",
29 },
30 {
31 number: "05",
32 question: "無料トライアルはありますか?",
33 answer:
34 "14日間の無料トライアルをご利用いただけます。クレジットカードの登録は不要で、すべての機能を制限なくお試しいただけます。",
35 },
36 {
37 number: "06",
38 question: "解約時のデータはどうなりますか?",
39 answer:
40 "解約後30日間はデータを保持し、エクスポート機能で全データをダウンロードいただけます。保持期間終了後は安全に削除いたします。",
41 },
42];
43
44export function FaqFloating001() {
45 const [openIndex, setOpenIndex] = useState<number | null>(null);
46
47 return (
48 <section className="bg-background py-28">
49 <div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
50 {/* ヘッダー */}
51 <div className="flex flex-col gap-6 sm:flex-row sm:items-end sm:justify-between">
52 <div>
53 <p className="text-[10px] uppercase tracking-[0.3em] text-muted-foreground">
54 FAQ
55 </p>
56 <h2 className="mt-3 text-2xl font-medium tracking-wide text-foreground sm:text-3xl">
57 よくあるご質問
58 </h2>
59 </div>
60 <p className="max-w-sm text-sm font-light leading-relaxed text-muted-foreground">
61 ご不明な点がございましたら、お気軽にお問い合わせください。
62 </p>
63 </div>
64
65 <div className="mt-4 h-px bg-border/40" />
66
67 {/* FAQ カードグリッド */}
68 <div className="mt-12 grid grid-cols-1 gap-4 sm:grid-cols-2">
69 {faqItems.map((item, i) => (
70 <div
71 key={i}
72 className="group relative rounded-lg border border-border/60 bg-background transition-colors duration-300 hover:border-border"
73 >
74 {/* コーナードット */}
75 <div className="absolute left-3 top-3 h-1 w-1 rounded-full bg-foreground/10" />
76 <div className="absolute right-3 top-3 h-1 w-1 rounded-full bg-foreground/10" />
77
78 <div className="p-6">
79 <button
80 onClick={() => setOpenIndex(openIndex === i ? null : i)}
81 className="flex w-full items-start gap-4 text-left"
82 >
83 <span className="mt-0.5 shrink-0 text-[10px] tracking-[0.2em] text-muted-foreground/40">
84 {item.number}
85 </span>
86 <span className="flex-1 text-sm font-medium tracking-wide text-foreground">
87 {item.question}
88 </span>
89 <span className="mt-0.5 shrink-0 text-muted-foreground/40">
90 <svg
91 className={`h-3.5 w-3.5 transition-transform duration-300 ${
92 openIndex === i ? "rotate-45" : ""
93 }`}
94 fill="none"
95 stroke="currentColor"
96 viewBox="0 0 24 24"
97 >
98 <path
99 strokeLinecap="round"
100 strokeLinejoin="round"
101 strokeWidth={1.5}
102 d="M12 4v16m8-8H4"
103 />
104 </svg>
105 </span>
106 </button>
107
108 <div
109 className={`overflow-hidden transition-all duration-300 ${
110 openIndex === i
111 ? "mt-4 max-h-48 opacity-100"
112 : "max-h-0 opacity-0"
113 }`}
114 >
115 <div className="h-px bg-border/40" />
116 <p className="pt-4 pl-[calc(10px+1rem)] text-sm font-light leading-relaxed text-muted-foreground">
117 {item.answer}
118 </p>
119 </div>
120 </div>
121 </div>
122 ))}
123 </div>
124
125 {/* フッター */}
126 <div className="mt-12 flex items-center justify-center gap-4">
127 <div className="h-px w-8 bg-border/40" />
128 <a
129 href="#"
130 className="inline-flex items-center gap-2 text-xs tracking-[0.15em] text-muted-foreground transition-colors hover:text-foreground"
131 >
132 お問い合わせ
133 <svg
134 className="h-3 w-3"
135 fill="none"
136 stroke="currentColor"
137 viewBox="0 0 24 24"
138 >
139 <path
140 strokeLinecap="round"
141 strokeLinejoin="round"
142 strokeWidth={1.5}
143 d="M17 8l4 4m0 0l-4 4m4-4H3"
144 />
145 </svg>
146 </a>
147 <div className="h-px w-8 bg-border/40" />
148 </div>
149 </div>
150 </section>
151 );
152}