FAQブロック
FAQ は、MUI 上に構築されたアコーディオン形式のよくある質問ブロックで、中央揃えのタイトル、サブタイトル、展開可能な質問と回答の項目を備えています。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-faq-block
yarn add @nodeblocks/frontend-faq-block
pnpm add @nodeblocks/frontend-faq-block
bun add @nodeblocks/frontend-faq-block
必要なもの
| 項目 | 用途 |
|---|---|
faqTitle | プライマリ見出し |
subtitle | タイトル下の補助テキスト |
items | アコーディオン行としてレンダリングされる Q&A ペア |
コンテンツはアプリ側で管理する
FAQ はアコーディオンの展開/折りたたみを内部で管理します。ページまたは CMS から faqTitle、subtitle、items を渡してください。各項目には question と answer の文字列が必要です。
コード例
- クイックスタート
- 複合コンポーネント
- ブロックのオーバーライド
ライブエディター
function Example() { const faqItems = [ { question: 'このサービスとは何ですか?', answer: 'ビジネス運営を効率的に管理するための包括的なプラットフォームです。', }, { question: 'どのように始めればよいですか?', answer: 'アカウントにサインアップし、プロフィールを完成させれば、すぐにすべての機能を使い始められます。', }, { question: '無料トライアルはありますか?', answer: 'はい、すべての機能にフルアクセスできる14日間の無料トライアルを提供しています。クレジットカードは不要です。', }, { question: 'サポートにはどう連絡できますか?', answer: 'メール、ライブチャット、または営業時間内のサポートホットラインでサポートチームに連絡できます。', }, ]; return ( <FAQ faqTitle="よくある質問" subtitle="サービスに関するよくある質問への回答をご覧ください" items={faqItems} /> ); }
結果
Loading...
FAQ.Title と FAQ.ItemList を直接構成し、各ブロックを sx でスタイルします。
ライブエディター
function Example() { const faqItems = [ { question: 'このサービスとは何ですか?', answer: 'ビジネス運営を効率的に管理するための包括的なプラットフォームです。', }, { question: 'どのように始めればよいですか?', answer: 'アカウントにサインアップし、プロフィールを完成させれば、すぐにすべての機能を使い始められます。', }, { question: '無料トライアルはありますか?', answer: 'はい、すべての機能にフルアクセスできる14日間の無料トライアルを提供しています。クレジットカードは不要です。', }, ]; return ( <FAQ faqTitle="よくある質問" subtitle="サービスに関するよくある質問への回答をご覧ください" items={faqItems} > <FAQ.Title sx={{ px: 2, py: 3, borderRadius: 2, bgcolor: 'grey.50', '& .MuiTypography-root:first-of-type': { letterSpacing: 1, textTransform: 'uppercase' }, }} /> <FAQ.ItemList sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 2, overflow: 'hidden', '& .nbb-faq-item': { '&::before': { opacity: 0 } }, }} /> </FAQ> ); }
結果
Loading...
defaultBlocks と defaultBlockOrder を使う関数の children で、ブロックの注入、デフォルトの差し替え、順序の制御を行います。
ライブエディター
function Example() { const faqItems = [ { question: 'このサービスとは何ですか?', answer: 'ビジネス運営を効率的に管理するための包括的なプラットフォームです。', }, { question: 'どのように始めればよいですか?', answer: 'アカウントにサインアップし、プロフィールを完成させれば、すぐにすべての機能を使い始められます。', }, { question: '無料トライアルはありますか?', answer: 'はい、すべての機能にフルアクセスできる14日間の無料トライアルを提供しています。クレジットカードは不要です。', }, { question: 'サポートにはどう連絡できますか?', answer: 'メール、ライブチャット、または営業時間内のサポートホットラインでサポートチームに連絡できます。', }, ]; return ( <FAQ faqTitle="よくある質問" subtitle="サービスに関するよくある質問への回答をご覧ください" items={faqItems} > {({ defaultBlocks }) => ({ blocks: { ...defaultBlocks, supportBanner: ( <Alert severity="info" sx={{ mb: 2 }}> お探しの内容が見つかりませんか?サポートチームにお問い合わせください。 </Alert> ), itemList: ( <FAQ.ItemList sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 2, overflow: 'hidden', bgcolor: 'background.paper', }} /> ), }, blockOrder: ['title', 'supportBanner', 'itemList'], })} </FAQ> ); }
結果
Loading...
ブロックのオーバーライドを使うタイミング
デフォルトの defaultBlockOrder は title、item、itemList です。ルートのレンダリングでは title と itemList を使用します。item はアコーディオンの細かいオーバーライドに利用できます。バナーの前置、デフォルトブロックの差し替え、セクションの並べ替えが必要な場合にオーバーライドを使い、items はルートコンポーネントに保持してください。
主要プロパティ
コアプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
faqTitle | ReactNode | はい | — | FAQ.Title でレンダリングされるプライマリ見出し |
subtitle | ReactNode | はい | — | タイトル下の補助テキスト |
items | { question: string; answer: string }[] | はい | — | FAQ.ItemList でアコーディオン行にマッピングされる FAQ エントリ |
レイアウトと構成プロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | ReactNode | function | いいえ | undefined | 複合サブコンポーネント(FAQ.Title、FAQ.ItemList)、またはレイアウトブロックの注入・並べ替え用の関数 ({ defaultBlocks, defaultBlockOrder }) => ({ blocks, blockOrder }) |
className | string | いいえ | undefined | ルートスタックのクラス名(nbb-faq) |
sx | SxProps | いいえ | undefined | ルートスタック用の MUI システムスタイル |
spacing | StackProps['spacing'] | いいえ | { xs: 5, sm: 6 } | ルートスタックの垂直方向の間隔 |
FAQ は StackProps(children を除く)を継承します。デフォルトの defaultBlockOrder: title、item、itemList。
サブコンポーネントのプロパティ
サブコンポーネントはコンテキストから読み取り、同じコンテンツキーをプロパティとして渡すとローカルで上書きできます。
| サブコンポーネント | 主要プロパティ | 継承 | ベース |
|---|---|---|---|
FAQ.Title | faqTitle、subtitle、children、spacing(デフォルト 1)、className、sx | StackProps | Stack + Typography |
FAQ.ItemList | items、activeIndex、toggleAccordion、children、className、sx | StackProps | Stack + Divider + FAQ.Item 行 |
FAQ.Item | question、answer、index、isActive、onToggle、className、sx | AccordionProps | Accordion + AccordionSummary + AccordionDetails + ExpandMore アイコン |
デフォルト UI ブロック
| ブロック | ベース | 備考 |
|---|---|---|
FAQ(ルート) | Stack | レスポンシブな間隔の縦レイアウト(nbb-faq) |
title(FAQ.Title) | Stack + Typography | 中央揃えのタイトル(variant="h6" / レスポンシブ h4)とサブタイトル(variant="h1") |
itemList(FAQ.ItemList) | Stack + Divider | items を上下に Divider 付きの FAQ.Item アコーディオンにマッピング |
item(FAQ.Item) | Accordion | Q. プレフィックス、太字の質問、回答本文を持つ単一行 |
デフォルトのルートレンダリング順序: title → itemList。
TypeScript
import * as React from 'react';
import { FAQ } from '@nodeblocks/frontend-faq-block';
import type { ReactNode } from 'react';
type FaqItem = {
question: string;
answer: string;
};
type FaqSectionProps = {
faqTitle: ReactNode;
subtitle: ReactNode;
items: FaqItem[];
};
export function FaqSection({ faqTitle, subtitle, items }: FaqSectionProps) {
return <FAQ faqTitle={faqTitle} subtitle={subtitle} items={items} />;
}