CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-markdown-to-jsx

Convert markdown to JSX with ease for React and React-like projects.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

custom-rendering.mddocs/

Custom Rendering

Complete control over individual rule rendering through custom render functions and rule system integration.

Capabilities

Custom Render Rule

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
});

Rule Type System

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();
  }
};

Parser State Access

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();
};

Advanced Rendering Patterns

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 })
  })
};

Error Handling in Custom Rendering

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();
  }
};

docs

advanced-configuration.md

component-interface.md

component-overrides.md

core-compilation.md

custom-rendering.md

index.md

utility-functions.md

tile.json