react-remark

repository·main·Indexed 42 days ago

https://github.com/remarkjs/react-remark

A library for rendering Markdown as React components using the remark and rehype ecosystems. Version 2.1.0 provides the <Remark> component for declarative rendering, as well as useRemark and useRemarkSync hooks for asynchronous and synchronous processing. It supports a unified pipeline allowing configuration of remark-parse, remark-rehype, and rehype-react via plugins and options.

Tokens
2.2K
Snippets
8
Records
10
Agent score
4%

What's inside react-remark

  1. How react-remark processes markdown

    main

    The react-remark architecture follows a unified pipeline that transforms raw markdown into React elements through several stages:

    1. Markdown $\rightarrow$ remark: Parses markdown into an mdast (Markdown Abstract Syntax Tree).
    2. remark plugins: Transform the mdast.
    3. remark-rehype: Converts mdast into hast (Hypertext Abstract Syntax Tree).
    4. rehype plugins: Transform the hast.
    5. rehype-react: Converts hast into React elements.
  2. Configure react-remark options

    main

    Both the useRemark hook and the <Remark> component accept an options object to configure the underlying unified/remark/rehype pipeline.

    Available configuration keys:

    • remarkParseOptions (Object): Configure how Markdown is parsed (matches remark-parse options).
    • remarkPlugins (Array): Remark plugins or custom plugins to transform markdown content (mdast) before translation to HTML.
    • remarkToRehypeOptions (Object): Configure how Markdown (mdast) is translated into HTML (hast) (matches remark-rehype options).
    • rehypePlugins (Array): Rehype plugins or custom plugins to transform HTML (hast) before translation to React elements.
    • rehypeReactOptions (Object): Configure how HTML (hast) is translated into React elements (matches rehype-react options).
    import { useRemark } from 'react-remark';
    import remarkGemoji from 'remark-gemoji';
    import rehypeSlug from 'rehype-slug';
    import rehypeAutoLinkHeadings from 'rehype-autolink-headings';
    
    const [reactContent, setMarkdownSource] = useRemark({
      remarkPlugins: [remarkGemoji],
      remarkToRehypeOptions: { allowDangerousHtml: true },
      rehypePlugins: [rehypeSlug, rehypeAutoLinkHeadings],
      rehypeReactOptions: {
        components: {
          p: (props) => <p className="custom-paragraph" {...props} />,
        },
      },
    });
  3. Use the useRemark hook

    main

    The useRemark hook provides a stateful way to manage markdown content and its rendered React output. It returns an array containing the rendered reactContent and a setMarkdownSource function to update the input string.

    Use this pattern for interactive markdown editors or when markdown content is fetched asynchronously.

    import React, { useEffect } from 'react';
    import { useRemark } from 'react-remark';
    
    const ExampleComponent = () => {
      const [reactContent, setMarkdownSource] = useRemark();
    
      useEffect(() => {
        setMarkdownSource('# markdown header');
      }, []);
    
      return reactContent;
    };
  4. Use the useRemarkSync hook for Server Side Rendering

    main

    The useRemarkSync hook is designed for synchronous rendering, making it suitable for Server Side Rendering (SSR).

    Warning: Some remark plugins are asynchronous. If you use asynchronous plugins, they will cause an error when used with useRemarkSync.

    import React from 'react';
    import { useRemarkSync } from 'react-remark';
    
    const ExampleComponent = () => {
      const reactContent = useRemarkSync('# markdown header');
    
      return reactContent;
    };
  5. Use the Remark component

    main

    The <Remark> component is a declarative way to render markdown. You can pass the markdown string as children to the component.

    For dynamic content, manage the markdown string in your own React state and pass it as children to <Remark>.

    import React, { useState } from 'react';
    import { Remark } from 'react-remark';
    
    const ExampleComponent = () => {
      const [markdownSource, setMarkdownSource] = useState('');
    
      return (
        <>
          <input
            type="text"
            onChange={({ currentTarget }) => setMarkdownSource(currentTarget.value)}
          />
          <Remark>{markdownSource}</Remark>
        </>
      );
    };
  6. Configure remark and rehype options

    main

    Both the hooks and the Remark component accept an options object to configure the underlying unified processing pipeline. This allows you to inject custom plugins and configure the behavior of remark-parse, remark-rehype, and rehype-react.

    Available Options (UseRemarkOptions / UseRemarkSyncOptions):

    • remarkParseOptions: Options for remark-parse.
    • remarkToRehypeOptions: Options for remark-rehype.
    • rehypeReactOptions: Options for rehype-react. Note that createElement and Fragment are automatically provided, but you can override other properties using PartialBy<RehypeReactOptions, 'createElement'>.
    • remarkPlugins: A PluggableList of plugins to use during the remark phase.
    • rehypePlugins: A PluggableList of plugins to use during the rehype phase.
    • onError (only in useRemark and Remark): A callback function (err: Error) => void triggered if processing fails.
  7. Use the Remark component for declarative markdown rendering

    main

    The Remark component is a declarative wrapper around the useRemark hook. You can pass markdown text as children, and the component will automatically handle the asynchronous processing and rendering lifecycle.

    Props:

    • children: The markdown string to be rendered.
    • ...useRemarkOptions: Any options compatible with UseRemarkOptions (see below).
    import { Remark } from 'react-remark';
    
    const App = () => (
      <Remark 
        remarkPlugins={[]} 
        rehypePlugins={[]} 
      >
        # This is markdown
      </Remark>
    );
  8. Use the useRemark hook for asynchronous markdown rendering

    main

    The useRemark hook provides an asynchronous way to transform markdown strings into React elements. It returns a tuple containing the current ReactElement (or null while loading) and a setter function to update the markdown source. This is ideal for handling large markdown files or when you want to avoid blocking the main thread during processing.

    Returns: [reactContent, setMarkdownSource]

    • reactContent: The rendered ReactElement or null.
    • setMarkdownSource: A function that accepts a string and triggers the asynchronous processing pipeline.
    import { useRemark } from 'react-remark';
    
    const MyComponent = () => {
      const [content, setMarkdown] = useRemark({
        remarkPlugins: [/* your plugins */],
        onError: (err) => console.error(err),
      });
    
      useEffect(() => {
        setMarkdown('# Hello World');
      }, [setMarkdown]);
    
      return <div>{content}</div>;
    };
  9. Use the useRemarkSync hook for synchronous markdown rendering

    main

    The useRemarkSync hook performs the markdown-to-React transformation synchronously. It is useful for small markdown strings where immediate rendering is required and you want to avoid the complexity of managing loading states or useEffect calls.

    Warning: Because this uses .processSync(), it may block the main thread if the markdown source is very large or the plugin pipeline is heavy.

    import { useRemarkSync } from 'react-remark';
    
    const MyComponent = ({ markdownString }: { markdownString: string }) => {
      const content = useRemarkSync(markdownString, {
        remarkPlugins: [],
        rehypePlugins: [],
      });
    
      return <div>{content}</div>;
    };