React-Markdownをカスタマイズする話
reactでのmarkdownを表示するライブラリ react-markdown のカスタマイズ方法をメモしておきます
今回のカスタマイズするポイントは以下です
- リンクを新規ウィンドウ(タブ)で開く
- コードブロックのシンタックスハイライト
カスタマイズの書き方
ReactMarkdownにて各要素のタグに関する処理はcomponentsに記載すればOKです
今回はリンク(a)とコードブロック(code)のカスタマイズを行います
<ReactMarkdown
components={{
a: AnchorTag,
code: CodeBlock,
}}
>
コンポーネントのカスタマイズ
リンクを新規ウィンドウ(タブ)で開く
リンク(a)にカスタム定義 AnchorTagを指定します
a: AnchorTag,
の部分です
const AnchorTag = ({ node, children, ...props }: any) => {
try {
new URL(props.href ?? "");
props.target = "_blank";
props.rel = "noopener noreferrer";
} catch (e) { }
return <a {...props}>{children}</a>;
}
ソースの解説は不要かな。
aのtargetとrelを指定しました
コードブロックのシンタックスハイライト
コードブロック(code)にカスタム定義 CodeBlockを指定します
code: CodeBlock,
CodeBlockでは、言語指定した場合にSyntaxHighlighterを使用します
今回はデザイン atomDarkを使っています
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
const CodeBlock = ({ inline, className, children, }: any) => {
if (inline) {
return <code className={className}>{children}</code>;
}
const match = /language-(\w+)/.exec(className || '');
if (!match) {
return <code className={className}>{children}</code>;
}
const lang = match && match[1] ? match[1] : '';
return (
<SyntaxHighlighter
style={atomDark}
language={lang}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
);
}
終いに
今回はreact-markdownのカスタマイズに関して書きました
一度定義したら変更することがないので忘れがちなので記事にしました
特にアンカー(a)は基本仕様が_blankだったかなと勘違いしてました
参考:ソース
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
type Props = {
children?: string | null | undefined;
};
const CustomReactMarkdown: React.FC<Props> = (props: Props) => {
return <ReactMarkdown
components={{
a: AnchorTag,
code: CodeBlock,
}}
>
{props.children}
</ReactMarkdown>
}
export default CustomReactMarkdown
const CodeBlock = ({ inline, className, children, }: any) => {
if (inline) {
return <code className={className}>{children}</code>;
}
const match = /language-(\w+)/.exec(className || '');
if (!match) {
return <code className={className}>{children}</code>;
}
const lang = match && match[1] ? match[1] : '';
return (
<SyntaxHighlighter
style={atomDark}
language={lang}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
);
}
const AnchorTag = ({ node, children, ...props }: any) => {
try {
new URL(props.href ?? "");
props.target = "_blank";
props.rel = "noopener noreferrer";
} catch (e) { }
return <a {...props}>{children}</a>;
}