markdown-to-jsxで画像にキャプションをつける

公開日時

このブログはContentfulでmarkdownを書いて、Next.js側でmarkdown-to-jsを使って変換を行っている。

これまで画像の記法は ![alt](url) を使っていたが、 ![alt](url "title") と指定すると title属性も指定できる。

そこでmarkdown-to-jsのoverridesを使ってtitleが指定されている場合はfigcaptionでキャプションを付与するようにした。

valheim2
キャプション例: ダンジョン飯
import Markdown from 'markdown-to-jsx'
import React from 'react'

type Props = {
  content: string
}

type CustomImageProps = {
  src: string
  title?: string
  alt?: string
}

const CustomImage = ({ src, title, alt }: CustomImageProps) => {
  if (title) {
    return (
      <figure>
        <img src={src} title={title} alt={alt} />
        <figcaption className="text-center">{title}</figcaption>
      </figure>
    )
  }
  return <img src={src} title={title} alt={alt} />
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const CustomParagraph = (props: any) => {
  return React.Children.toArray(props.children).some((child) => typeof child === 'string') ? (
    <p {...props} />
  ) : (
    <div {...props} />
  )
}

export const PostContent = ({ content }: Props) => {
  return (
    <div className="max-w-2xl mx-auto">
      <Markdown
        className="prose dark:prose-dark"
        options={{
          overrides: {
            img: {
              component: CustomImage,
            },
            p: {
              component: CustomParagraph,
            },
          },
        }}
      >
        {content}
      </Markdown>
    </div>
  )
}

imgタグのみoverrideしただけだとconsoleに以下のWarningが出てしまった。

Warning: validateDOMNesting(...): <figure> cannot appear as a descendant of <p>.

そこで↓のissueにあるようにpタグもoverrideするように対応した。

これでmarkdownで画像キャプションが使えるようになった。

参考


Related #next.js

SharedArrayBuffer updates in Android Chrome 88 and Desktop Chrome 92

クロスオリジン分離対応を実施

react-hook-formとReact Datepickerを組み合わせる

Hook FormのControllerを使う

Next.jsで生成したサイトで特定のページのみnoindexを設定する

タグに紐づく記事一覧ページはnoindexにした

Next.jsでAdsenseタグを埋め込んだら Only one AdSense head tag supported per page エラーが発生

Only one AdSense head tag supported per page. The second tag is ignored.