22
loading...
This website collects cookies to deliver better user experience
pre
block and then each line is split into a div
. Then, each word or symbol is split into spans
. This is how the styler will apply individual styles to each word or symbol. It is important to understand this, because we will need to know which HTML elements to target if we want to style our code blocks with the correct syntax highlighting.# npm
npm install --save prism-react-renderer
# yarn
yarn add prism-react-renderer
SyntaxHighlighter
. The below code is a basic version of the component, copy the code below and we can go through what it is doing.import Highlight, { defaultProps } from "prism-react-renderer";
const SyntaxHighlighter = ({ children }) => {
const code = children.props.children;
return (
<Highlight {...defaultProps} code={code}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style }}>
{tokens.slice(0, -1).map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
);
};
export default SyntaxHighlighter;
<Highlight />
component, it styles our code blocks in our MDX files. The second is the { defaultProps }
object, this gets spread into the Highlight
component and will provide us with some default theming.SyntaxHighlighter
component and pass it a children
prop.code
and access the mdx code through our children
prop. It stores the MDX code block so we can then pass it into the <Highlight />
component.Highlight
component we create an anonymous function with the props className, style, tokens, getLineProps, getTokenProps
.pre
block. First, we slice
all lines and pass them into a div
element. Within the div
we are going to put each word and token into span
elements. Essentially, what happens here is the getLineProps
& getTokenProps
apply things like the styling to your syntax.defaultProps
uses the duotoneDark
theme as a default. We will see how to customize themes later.import theme from "prism-react-renderer/themes/themeName";
and adding the theme prop to our Highlight
component's props.import Highlight, { defaultProps } from "prism-react-renderer";
import theme from "prism-react-renderer/themes/nightOwlLight";
const SyntaxHighlighter = ({ children }) => {
const code = children.props.children;
return (
<Highlight
{...defaultProps}
code={code}
theme={theme}
>
// ...
border-radius
? Well, let's see how to do that now with styled-components.pre
block which, we will call PreBlock
. Before we do that, we need to wrap the pre
block in a div
called CodeBlockContainer
. The SyntaxHighlighter
should now look like the code below.const SyntaxHighlighter= ({ children }) => {
//...
<CodeBlockContainer>
<PreBlock className={className}>
{tokens.slice(0, -1).map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</PreBlock>
</CodeBlockContainer>;
//...
};
pre
block and wrapped it in a CodeBlockContainer
, this allows us to add some styling to the code blocks.const CodeBlockContainer = styled.div`
position: relative;
margin-top: 48px;
margin-bottom: 60px;
transition: all 200ms ease-in 0s;
`;
const PreBlock = styled.pre`
font-family: Arial, Helvetica, sans-serif;
font-size: 18px;
outline-offset: 2px;
overflow-x: auto;
margin-left: -32px;
margin-right: -32px;
padding: 32px;
min-height: 50px;
border: 1px solid rgba(230, 230, 230, 1);
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
max-width: calc(100% + 64px);
`;
pre
block.js
next to the three backticks. That tells markdown that the language is JavaScript, you could use CSS or HTML if the code was written in those languages. In fact there is a whole list of languages you can use.SyntaxHighlighter
component like so children_.props.className?.replace("language-", "").trim();
. You will need to save the value of this expression in a const
and then pass the Highlighter
a language prop.const SyntaxHighlighter = ({ children }) => {
const code = children.props.children;
const language = children.props.className?.replace("language-", "").trim();
return (
<Highlight {...defaultProps} code={code} language={language}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<CodeSnippetContainer>
<PreBlock className={className} style={{ ...style }}>
{tokens.slice(0, -1).map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</PreBlock>
</CodeSnippetContainer>
)}
</Highlight>
);
};
export default CodeBlock;
language
variable. To do this we add a LanguageHeadingContainer
inside of the CodeSnippetContainer
.const Syntaxhighligher //...
<CodeSnippetContainer>
{language && (
<LanguageHeadingContainer>{language.toUpperCase()}</LanguageHeadingContainer>
)}
<PreBlock> //...
LanguageHeadingContainer
if language is present in our markdown. Next, we need to add the styling for the LanguageHeadingContainer
.const CodeBlockWrapper = styled.div`
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
border-width: 1px 1px 0px;
border-style: solid;
border-color: rgba(230, 230, 230, 1);
background-color: rgb(231, 232, 235);
padding: 0.75rem 1.25rem;
margin-left: -32px;
margin-right: -32px;
font-family: font-family: Arial, Helvetica, sans-serif;;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 700;
color: hsl(220deg, 23%, 5%);
text-align: right;
`;
SyntaxHighlighter
component with our blog. This component will work with other popular MDX
libraries but, I am going to show you how we do it with mdx-bundler.import SyntaxHighlight from "components/syntaxHighlighter";
<SyntaxHighlighter
children={```
js
const codeBlock = () => {
// does something
}
```}
/>;
SyntaxHighlighter
we will automatically convert them using mdx-bundler.SyntaxHighlighter
component to the mdx-bundler <Component />
arguments. You will need to import the SyntaxHighlighter
component into your [slug].js
file.// [slug].js
<Component
components={{
pre: SyntaxHighlighter,
}}
/>
SyntaxHighligther
component whenever it sees a pre
block.var myCustomTheme = {
plain: {
color: "#d6deeb",
backgroundColor: "#011627",
fontFamily: "var(--font-family-syntax)",
fontSize: "16px",
},
styles: [
{
types: ["changed"],
style: {
color: "rgb(162, 191, 252)",
fontStyle: "italic",
},
},
{
types: ["deleted"],
style: {
color: "rgba(239, 83, 80, 0.56)",
fontStyle: "italic",
},
},
{
types: ["inserted", "attr-name"],
style: {
color: "rgb(173, 219, 103)",
fontStyle: "italic",
},
},
{
types: ["comment"],
style: {
color: "rgb(99, 119, 119)",
fontStyle: "italic",
},
},
{
types: ["string", "url"],
style: {
color: "rgb(173, 219, 103)",
},
},
{
types: ["variable"],
style: {
color: "rgb(214, 222, 235)",
},
},
{
types: ["number"],
style: {
color: "rgb(247, 140, 108)",
},
},
{
types: ["builtin", "char", "constant", "function"],
style: {
color: "rgb(130, 170, 255)",
},
},
{
// This was manually added after the auto-generation
// so that punctuations are not italicised
types: ["punctuation"],
style: {
color: "rgb(199, 146, 234)",
},
},
{
types: ["selector", "doctype"],
style: {
color: "rgb(199, 146, 234)",
fontStyle: "italic",
},
},
{
types: ["class-name"],
style: {
color: "rgb(255, 203, 139)",
},
},
{
types: ["tag", "operator", "keyword"],
style: {
color: "rgb(127, 219, 202)",
},
},
{
types: ["boolean"],
style: {
color: "rgb(255, 88, 116)",
},
},
{
types: ["property"],
style: {
color: "rgb(128, 203, 196)",
},
},
{
types: ["namespace"],
style: {
color: "rgb(178, 204, 214)",
},
},
],
};
export default myCustomTheme;
mycustomTheme.js
file that you can then import into the SyntaxHighlighter
component. Once you've imported it, you just need to pass myCustomTheme
as an argument in the Highligther's
theme prop.<Highlight
{...defaultProps}
code={code}
language={language}
theme={myCustomTheme}
>