Web

Sintaks Hightlighting pada React Markdown

4 min read
cover-thumbnail

Jika anda membangun website anda menggunakan Strapi atau dari sumber source markdown yang lain maka kalian akan mengetahui bahwa data yang kita ambil dari untuk menampilkan content adalah dalam bentuk rich-text, namun secara default Markdown tidak mendukung untuk syntax hightlighting.

Sehingga jika anda ingin menambahakan sintaks highlighting pada artikel yang anda buat maka anda perlu menambahakan beberapa package tambahan agar tampilan sintaks pada blog anda menjadi lebih menarik.

Apa saja yang dibutuhkan

kita membutuhkan react-markdown dan react-syntax-hightlighter. React markdown kita gunakan untuk rendering dari markdown ke HTML dan react syntax highlighter untuk menangani highlighting.

Terminal window
npm install react-markdown react-syntax-hightlighter

atau

Terminal window
yarn add react-markdown react-syntax-hightlighter

Basic React Markdown

Untuk menampilkan sebuah konten dalam bentuk markdown agar dapat tampil, anda dapat mengirim data content anda kedalam ReactMarkdown seperti berikut

const Article = ({ article }) => <ReactMarkdown children={article.content} />;

Menambahkan code Component

Sekarang anda dapat menambahkan syntaks highlighting dengan menambahkan value pada prop components seperti berikut.

import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { materialDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
const Article = ({ article }) => (
<ReactMarkdown
children={article.content}
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || "");
return !inline && match ? (
<SyntaxHighlighter
children={String(children).replace(/\n$/, "")}
style={materialDark}
language={match[1]}
PreTag="div"
// {...props}
/>
) : (
<code
className={`bg-zinc-200 dark:bg-zinc-700 p-1 text-black dark:text-white rounded ${className}`}
{...props}
>
{children}
</code>
);
},
}}
/>
);

Prop components pada markdown menerima beberapa key dan value, salah satu keynya yaitu code, dan kita bisa beri value berupa CodeBlock yang telah kita buat.

Disini saya menggunakan tema materialDark, anda bisa explore Color Scheme sesuai dengan project anda sendiri.

Saya juga menggunakan tailwind.css untuk styling beberapa elemen seperti pada tag code. Selain itu saya juga override untuk beberapa style pada tailwind typography. Jika kalian menggunakan metode styling yang lain anda bisa skip kode dibawah.

module.exports = {
// ...
theme: {
extend: {
typography: {
DEFAULT: {
css: {
pre: {
backgroundColor: "none",
padding: "0 !important",
marginLeft: "0 !important",
marginRight: "0 !important",
marginTop: "0 !important",
borderRadius: "0.25rem !important",
marginBottom: "10px !important",
},
"pre div ": {
margin: "0px !important",
},
code: {
color: "var(--primary-text)",
backgroundColor: "var(--primary-inline-code)",
fontWeight: 400,
padding: "2px 5px",
},
"code::before": {
content: '""',
},
"code::after": {
content: '""',
},
},
},
},
},
},
plugins: [require("@tailwindcss/typography")],
};

Pada kode diatas kita hanya mereset beberapa style seperti override style nya agar menghilangkan margin, hapus tanda petik pada blok kode dll.

Tampilkan nama bahasa pemrograman yang digunakan.

Untuk menampilkan nama bahasa pemrograman sesuai dengan blok kode kita kita dapat memodifikasi code yang telah kita buat. Kita dapat melakukan ini dengan membungkus SyntaxHightlighter dengan sebuah div dan beri posisi relative lalu didalam div tersebut buatlah suatu paragraf dengan posisi absolute. Paragraf inilah yang nantinya akan menampilkan bahasa pemrograman yg kita gunakan.

Disini saya menggunakan component Language untuk menampilkan nama extension pada syntax highlight kita.

import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { materialDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
const Article = ({ article }) => (
<ReactMarkdown
children={article.content}
components={{
code({ node, inline, className, children, ...props }) {
const match =
className !== undefined ? className.replace("language-", "") : true;
return !inline && match ? (
<div className="relative">
{(match !== "shell" || match === null) && (
<Language match={match} />
)}
<SyntaxHighlighter
children={String(children).replace(/\n$/, "")}
style={materialDark}
language={match}
PreTag="div"
{...props}
/>
</div>
) : (
<code
className={`bg-zinc-200 dark:bg-zinc-700 p-1 text-black dark:text-white rounded ${className}`}
{...props}
>
{children}
</code>
);
},
}}
/>
);

Berikut merupakan component Language.js

language.js
import classNames from "classnames";
import { languageMap, shortNameMap } from "./constant";
const Language = ({ match }) => {
return (
<span
className={classNames(
languageMap[match],
`font-monospace text-sm tracking-wide rounded-b-md absolute right-2 z-40 top-0 px-2 py-1`
)}
>
{shortNameMap(match)}
</span>
);
};
export default Language;

Pada Language.js kita mengimpor languageMap dan shortNameMap. file languageMap berisi style classname untuk masing-masing bahasa pemrograman, sedangkan shortNameMap berfungsi untuk mengconvert beberapa bahasa permrograman menjadi nama file extensinya saja.

export const languageMap = {
html: "bg-[#E34C26] text-black",
css: "bg-[#1572B6] text-white",
javascript: "bg-[#F0DB4F] text-black",
typescript: "bg-[#007ACC] text-black",
// ...other
};
export const shortNameMap = (match) => {
const listExtensionOfLanguage = {
javascript: "js",
typescript: "ts",
csharp: "cs",
python: "py",
// ...other
};
return listExtensionOfLanguage[match] || match;
};

Untuk contoh diatas saya menggunakan tailwindcss untuk melakukan styling. di file inilah kita melakukan customisasi warna text & background

Sekarang blok code anda akan terlihat lebih menarik dengan syntax hightlighting yang telah kita terapkan.

Terima kasih 🙂