Preview
import type { ComponentProps } from "react";
const MyComponent = (props: ComponentProps<"div">) => {
return <div {...props}>Hello, World!</div>;
};
export default MyComponent;Installation
shadcn/ui
shadcn/ui Command
pnpm dlx shadcn@latest add https://code-blocks.pheralb.dev/r/mdx-sugar-high.jsonManual
Before creating the MDX component, make sure you have the basic component structure:
react
Code Block
The main structure of the Code Block component with header and content areas.
- Install the following dependencies:
MDX Types
pnpm i @types/mdx -D- Create the Copy Button component:
react
Copy Button
A button component to copy content to the clipboard.
- Create a
react-to-textutility to get plain text frompreelements:
react-to-text
import {
isValidElement,
type ReactNode,
type JSXElementConstructor,
} from "react";
type ResolverMap = Map<
string | JSXElementConstructor<object>,
(props: object) => string
>;
const reactToText = (node: ReactNode, resolvers?: ResolverMap): string => {
if (node == null || typeof node === "boolean") return "";
if (typeof node === "string" || typeof node === "number") return String(node);
if (Array.isArray(node))
return node.map((n) => reactToText(n, resolvers)).join("");
if (isValidElement(node)) {
const resolver = resolvers?.get(
node.type as string | JSXElementConstructor<object>,
);
if (resolver) return resolver(node.props as object);
return reactToText(
(node.props as { children?: ReactNode }).children,
resolvers,
);
}
return "";
};
export { reactToText };Highlighter Setup
- Setup Sugar-High highlighter:
sugar-high
Sugar-High Highlighter
The main highlighter utility to render syntax highlighted code.
- Create your
PreSugarHighComponentcomponent:
mdx-sugar-high
import type { ComponentProps } from "react";
import type { MDXComponents } from "mdx/types";
import { highlight } from "@/utils/sugar-high/highlight";
import { reactToText } from "@/utils/react-to-text";
import {
CodeBlock,
CodeBlockContent,
} from "@/components/code-block/code-block";
import { CopyButton } from "@/components/code-block/copy-button";
type PreProps = ComponentProps<"pre">;
const PreSugarHighComponent: MDXComponents = {
pre: ({ children }: PreProps) => {
const content = reactToText(children);
const codeHTML = highlight({
code: content,
});
return (
<CodeBlock className="group/code-block">
<CodeBlockContent className="relative">
<CopyButton
content={content}
className="sticky top-3 right-3 z-50 float-right rounded-md text-neutral-950 opacity-0 transition-opacity group-hover/code-block:opacity-100 hover:opacity-70 dark:text-neutral-50"
/>
<pre className="sh-pre">
<code dangerouslySetInnerHTML={{ __html: codeHTML }} />
</pre>
</CodeBlockContent>
</CodeBlock>
);
},
};
export { PreSugarHighComponent };- Usage:
In your MDX Components object, add the new PreSugarHighComponent component:
import type { MDXComponents as MDXComponentsType } from "mdx/types";
import { PreSugarHighComponent } from "@/components/code-block/pre-sugar-high";
const MDXComponents: MDXComponentsType = {
...PreSugarHighComponent,
};