Convert markdown to JSX with ease for React and React-like projects.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Complete control over individual rule rendering through custom render functions and rule system integration.
Override the rendering of specific markdown elements with complete control over the output.
/**
* Custom render rule function for complete rendering control
* @param next - Function to call for default rendering behavior
* @param node - Current AST node being rendered
* @param renderChildren - Function to render child nodes
* @param state - Current parser state with key for React elements
* @returns Custom React node or result of calling next()
*/
type RenderRuleFunction = (
next: () => React.ReactNode,
node: ParserResult,
renderChildren: RuleOutput,
state: State
) => React.ReactNode;
interface CustomRenderingOptions {
renderRule?: RenderRuleFunction;
}
type RuleOutput = (
ast: ParserResult | ParserResult[],
state: State
) => React.JSX.Element;Usage Examples:
import { compiler, RuleType } from "markdown-to-jsx";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
// Custom rendering for code blocks with syntax highlighting
const customRenderRule = (next, node, renderChildren, state) => {
// Handle code blocks specially
if (node.type === RuleType.codeBlock) {
return (
<SyntaxHighlighter
key={state.key}
language={node.lang || 'text'}
className="syntax-highlighted"
>
{node.text}
</SyntaxHighlighter>
);
}
// Handle headings with custom anchors
if (node.type === RuleType.heading) {
const id = node.id;
const HeadingTag = `h${node.level}`;
return (
<HeadingTag key={state.key} id={id} className={`heading-${node.level}`}>
<a href={`#${id}`} className="heading-anchor" aria-hidden="true">
#
</a>
{renderChildren(node.children, state)}
</HeadingTag>
);
}
// Handle links with external link indicators
if (node.type === RuleType.link) {
const isExternal = node.target.startsWith('http');
return (
<a
key={state.key}
href={node.target}
title={node.title}
target={isExternal ? '_blank' : undefined}
rel={isExternal ? 'noopener noreferrer' : undefined}
className={isExternal ? 'external-link' : 'internal-link'}
>
{renderChildren(node.children, state)}
{isExternal && <span className="external-icon">🔗</span>}
</a>
);
}
// Use default rendering for all other elements
return next();
};
const result = compiler(markdownContent, {
renderRule: customRenderRule
});Comprehensive set of rule types for identifying and handling different markdown elements.
/**
* Enumeration of all supported markdown rule types
* Values may change between versions - use constants, not hardcoded strings
*/
const RuleType: {
readonly blockQuote: "0";
readonly breakLine: "1";
readonly breakThematic: "2";
readonly codeBlock: "3";
readonly codeFenced: "4";
readonly codeInline: "5";
readonly footnote: "6";
readonly footnoteReference: "7";
readonly gfmTask: "8";
readonly heading: "9";
readonly headingSetext: "10";
readonly htmlBlock: "11";
readonly htmlComment: "12";
readonly htmlSelfClosing: "13";
readonly image: "14";
readonly link: "15";
readonly linkAngleBraceStyleDetector: "16";
readonly linkBareUrlDetector: "17";
readonly linkMailtoDetector: "18";
readonly newlineCoalescer: "19";
readonly orderedList: "20";
readonly paragraph: "21";
readonly ref: "22";
readonly refImage: "23";
readonly refLink: "24";
readonly table: "25";
readonly tableSeparator: "26";
readonly text: "27";
readonly textBolded: "28";
readonly textEmphasized: "29";
readonly textEscaped: "30";
readonly textMarked: "31";
readonly textStrikethroughed: "32";
readonly unorderedList: "33";
};Usage Examples:
import { RuleType } from "markdown-to-jsx";
const advancedRenderRule = (next, node, renderChildren, state) => {
switch (node.type) {
case RuleType.codeBlock:
case RuleType.codeFenced:
// Handle both types of code blocks
return <CustomCodeBlock key={state.key} {...node} />;
case RuleType.image:
// Custom image handling with lazy loading
return (
<img
key={state.key}
src={node.target}
alt={node.alt}
title={node.title}
loading="lazy"
className="responsive-image"
/>
);
case RuleType.table:
// Custom table with sorting
return <SortableTable key={state.key} data={node} />;
case RuleType.gfmTask:
// Custom task list item
return (
<CustomTaskItem
key={state.key}
completed={node.completed}
onChange={handleTaskToggle}
/>
);
case RuleType.blockQuote:
// Enhanced blockquotes with alert styling
const alertType = node.alert?.toLowerCase();
return (
<blockquote
key={state.key}
className={alertType ? `alert alert-${alertType}` : 'blockquote'}
>
{renderChildren(node.children, state)}
</blockquote>
);
default:
return next();
}
};Access and utilize parser state information for context-aware rendering.
/**
* Parser state object providing context about current parsing location
*/
interface State {
/** True if currently inside an anchor link */
inAnchor?: boolean;
/** True if parsing within HTML context */
inHTML?: boolean;
/** True if parsing in inline context */
inline?: boolean;
/** True if currently within a table */
inTable?: boolean;
/** React key for current element */
key?: React.Key;
/** True if currently within a list */
list?: boolean;
/** Previous capture string for context */
prevCapture?: string;
/** True if parsing in simple inline context */
simple?: boolean;
}Usage Examples:
const contextAwareRenderRule = (next, node, renderChildren, state) => {
// Different rendering based on context
if (node.type === RuleType.text) {
// Special handling for text in different contexts
if (state.inTable) {
return <span key={state.key} className="table-text">{node.text}</span>;
} else if (state.inAnchor) {
return <span key={state.key} className="link-text">{node.text}</span>;
} else if (state.list) {
return <span key={state.key} className="list-text">{node.text}</span>;
}
}
// Different link behavior based on context
if (node.type === RuleType.link && state.inTable) {
// Simplified links in tables
return (
<a key={state.key} href={node.target} className="table-link">
{renderChildren(node.children, state)}
</a>
);
}
return next();
};Complex rendering scenarios combining multiple techniques for sophisticated output.
Usage Examples:
import { compiler, RuleType } from "markdown-to-jsx";
// Rendering with plugins and extensions
const pluginRenderRule = (next, node, renderChildren, state) => {
// LaTeX math rendering
if (node.type === RuleType.codeBlock && node.lang === 'latex') {
return (
<div key={state.key} className="math-block">
<TeX math={node.text} block />
</div>
);
}
// Mermaid diagram rendering
if (node.type === RuleType.codeBlock && node.lang === 'mermaid') {
return (
<div key={state.key} className="mermaid-diagram">
<MermaidDiagram definition={node.text} />
</div>
);
}
// Interactive code examples
if (node.type === RuleType.codeBlock && node.lang === 'jsx-live') {
return (
<LiveCodeEditor
key={state.key}
code={node.text}
scope={{ React, useState, useEffect }}
/>
);
}
// Custom footnote handling
if (node.type === RuleType.footnoteReference) {
return (
<sup key={state.key}>
<a
href={node.target}
className="footnote-ref"
onClick={(e) => {
e.preventDefault();
scrollToFootnote(node.text);
}}
>
{node.text}
</a>
</sup>
);
}
return next();
};
// Conditional rendering based on configuration
const createConditionalRenderer = (config) => (next, node, renderChildren, state) => {
// Only render images if allowed
if (node.type === RuleType.image && !config.allowImages) {
return <span key={state.key}>[Image: {node.alt}]</span>;
}
// Filter out certain HTML elements
if (node.type === RuleType.htmlBlock && config.blockedTags.includes(node.tag)) {
return <span key={state.key}>[Blocked HTML element]</span>;
}
// Add analytics to links
if (node.type === RuleType.link) {
return (
<a
key={state.key}
href={node.target}
onClick={() => config.trackLink(node.target)}
>
{renderChildren(node.children, state)}
</a>
);
}
return next();
};
// Usage with custom configuration
const secureOptions = {
renderRule: createConditionalRenderer({
allowImages: false,
blockedTags: ['script', 'iframe', 'object'],
trackLink: (url) => analytics.track('link_click', { url })
})
};Robust error handling for custom render functions to prevent rendering failures.
const safeRenderRule = (next, node, renderChildren, state) => {
try {
// Custom rendering logic that might throw
if (node.type === RuleType.codeBlock) {
return <ComplexCodeRenderer key={state.key} code={node.text} />;
}
return next();
} catch (error) {
// Fallback to default rendering on error
console.warn('Custom rendering failed:', error);
return next();
}
};