AstroブログにQA機能を追加!FAQコンポーネント実装

AstroブログにQA機能を追加!FAQコンポーネント実装
記事内に商品プロモーションを含む場合があります

ブログを書く際に、以下のような QA コンテンツを使いたくなる場面はないでしょうか?

QAコンテンツの画像

自分自身 Astro でブログを書いている中で、QA コンテンツを使いたくなる場面がありました。しかし、デフォルトの Markdown の記法の中で上記のような QA コンテンツを表現する記法がなかったため独自の QA 記法を追加するために mdx で使えるコンポーネントを作成しました

本記事では、その QA コンポーネントについてまとめています

コンポーネントではなくプラグインで QA コンテンツを表示する方法も別途解説しているので、興味があれば読んでみてください!

mdx でコンポーネントを使う方法

Astro では mdx インテグレーションをインストールすると Astro コンポーネントや UI フレームワークコンポーネントを mdx ファイルで使用できるようになります。こちらについてはここでは詳しくは説明しないので、適宜 Astro Docs を参照してください

mdx ファイルにコンポーネントをインポートする方法はいくつかあって、まず公式 Doc で説明されている方法は各 mdx ファイルでコンポーネントをインポートして利用する方法です

---
layout: ../layouts/BaseLayout.astro
title: About me
---
import Button from '../components/Button.astro';
import ReactCounter from '../components/ReactCounter.jsx';

私は**火星**に住んでいますが、気軽に<Button title="お問い合わせ" />までご連絡ください。

以下は、MDXで動作するカウンターコンポーネントです。

<ReactCounter client:load />

しかし、この方法では mdx ファイルを作成するたびにコンポーネントをインポートしなければならず、少し手間です

そこで、次の選択肢に上がってくるのがコンテンツがレンダリングされる際に生成される <Content /> コンポーネントの引数にコンポーネントを渡す方法です。詳しくは Astro Docs を見ていただきたいのですが、この方法を使えば各 mdx ファイルでコンポーネントをインポートすることなくコンポーネントを使うことができるようになります

src/pages/render-example.astro

---
import { getEntry } from 'astro:content';
const entry = await getEntry('blog', 'blog-1');
const { Content, headings } = await entry.render();
import Toc from "./components/Toc.astro";
---
<p>公開日: {entry.data.published.toDateString()}</p>
<Content components={{ Toc }} />

上記の方法でも良いと思いますが、個人的にお勧めしたいのは astro-auto-import という Astro のインテグレーションを使用する方法です。このインテグレーションを使うと、コンポーネントや他のモジュールを自動インポートしてくれるので、インポートせずに mdx ファイルでコンポーネントにアクセスできるようになります

設定は簡単で astro-auto-import をプロジェクトにインストールして astro.config.mjs ファイルで以下のように AutoImport をインポートして設定に追加するだけです。自分自身は imports オプションにファイル名を渡す運用をしています!

terminal
$ yarn add astro-auto-import
astro.config.mjs
import { defineConfig } from 'astro/config';
import AutoImport from 'astro-auto-import';
import mdx from '@astrojs/mdx';

export default defineConfig({
  integrations: [
    AutoImport({
      imports: [
        './src/components/Toc.astro'
      ],
    }),
    mdx(),
  ],
});

これで mdx ファイルでコンポーネントを利用できるようになるので、あとは QA コンテンツ用のコンポーネントを実装していきます

QAコンテンツの表現方法

HTML Living Standard によると QA コンテンツを表現する際は dl / dt / dd タグを利用するのが良さそうです。そのため、HTML に変換した際に以下のような構成になるように実装していきます

HTML
<dl>
  <dt> Question1
  <dd> Answer1
  <dt> Question2
  <dd> Answer2
</dl>

QAコンテンツ用のコンポーネント

今回は QA コンテンツ用に2つのコンポーネントを実装しました

1つ目は QA の本文を囲う dl タグを表現するコンポーネントです

src/layouts/shortcodes/FaqWrapper.jsx
function FaqWrapper({ children }) {
  return (
    <dl className="faq">{children}</dl>
  );
}

export default FaqWrapper;

2つ目は QA を表現するコンポーネントです。引数の q に質問文を渡して、引数の a に回答文を渡すことで QA を表示することができます

src/layouts/shortcodes/Faq.jsx
function Faq({ q, a }) {
  return (
    <>
      <dt className="question">{q}</dt>
      <dd className="answer">{a}</dd>
    </>
  );
}

export default Faq;

mdx では Faq コンポーネントの引数に QA を渡して、QA コンテンツ群を FaqWrapper コンポーネントで囲うことで利用することができます

mdx
<FaqWrapper>
  <Faq 
    q="これは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数です"
    a="これは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数です"
  />

  <Faq 
    q="これは質問の時に使う引数です"
    a="これは回答の時に使う引数です"
  />
</FaqWrapper>

あとは自分好みでスタイルを当てたら以下のように QA コンテンツを表現することができるようになります

これは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数ですこれは質問の時に使う引数です
これは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数ですこれは回答の時に使う引数です
これは質問の時に使う引数です
これは回答の時に使う引数です

参考資料

Recommend
こんな記事も読まれています!