FumaDocs React Component to Display Code from Github Repos

The GithubCodeBlock component allows you to embed and display code from GitHub repositories directly in your Fuma Docs application. It supports line extraction, syntax highlighting, and line highlighting features. Installation You need to have fumadocs setup ready and running Step 1: Copy following code anywhere into your components import * as Base from "fumadocs-ui/components/codeblock"; import { highlight } from "fumadocs-core/highlight"; import { transformerMetaHighlight } from "@shikijs/transformers"; // Types export interface CodeBlockProps { code: string; wrapper?: Base.CodeBlockProps; lang: string; highlightLines?: string; } interface GithubCodeBlockProps { url: string; extractLines?: boolean; highlightLines?: string; wrapper?: Base.CodeBlockProps; } interface GitHubReference { rawUrl: string; fromLine?: number; toLine?: number; highlightLines?: string; } // Helper functions function formatHighlightLines(highlightLines?: string): string | undefined { if (!highlightLines) return undefined; return highlightLines.startsWith("{") && highlightLines.endsWith("}") ? highlightLines : `{${highlightLines}}`; } function getLanguageFromUrl(url: string): string { try { return url.split(".").pop()?.toLowerCase() || ""; } catch { return ""; } } function parseGitHubUrl(url: string): GitHubReference { try { // Split the URL to separate the line reference part const [githubUrl, loc] = url.split("#"); if (!githubUrl) { throw new Error("Invalid GitHub URL"); } // Initialize line reference variables let fromLine: number | undefined; let toLine: number | undefined; let highlightLines: string | undefined; // Parse line references if present if (loc) { const lineParts = loc.split("-"); if (lineParts[0]?.startsWith("L")) { fromLine = parseInt(lineParts[0].slice(1), 10) - 1; if (lineParts[1]?.startsWith("L")) { toLine = parseInt(lineParts[1].slice(1), 10) - 1; } else { toLine = fromLine; } // Always generate highlight lines from location // These will be used if no explicit highlightLines prop is provided if (fromLine !== undefined && toLine !== undefined) { const startLine = fromLine + 1; const endLine = toLine + 1; highlightLines = startLine === endLine ? `{${startLine}}` : `{${startLine}-${endLine}}`; } } } // Parse GitHub URL to create raw URL const urlObj = new URL(githubUrl); const pathParts = urlObj.pathname.split("/").slice(1); if (pathParts.length { if (line.length === 0) return indent; const spaces = line.match(/^\s+/); return spaces ? Math.min(indent, spaces[0].length) : 0; }, Infinity ); // Remove common indentation and join lines return selectedLines .map((line) => { if (line.length === 0) return line; return line.slice(commonIndent lines from URL loc const formattedHighlightLines = formatHighlightLines( highlightLines || reference.highlightLines ); // Fetch the code content, extracting specific lines if needed const code = await fetchCode( reference.rawUrl, extractLines ? reference.fromLine : undefined, extractLines ? reference.toLine : undefined ); const lang = getLanguageFromUrl(reference.rawUrl); return ( ); } catch (error) { console.error("Error in GithubCodeBlock:", error); return ( ); } } Step 2: Add to MDX Components import defaultMdxComponents from "fumadocs-ui/mdx"; import type { MDXComponents } from "mdx/types"; import GithubCodeBlock from "./components/github-code-block"; export function getMDXComponents(components?: MDXComponents): MDXComponents { return { ...defaultMdxComponents, GithubCodeBlock: GithubCodeBlock, ...components, }; } Basic Usage Props The component accepts the following props: Prop Type Default Description url string (required) GitHub URL to the file you want to display extractLines boolean false Whether to extract specific lines from the file highlightLines string undefined Lines to highlight in the format "{1,3-4}" wrapper object undefined CodeBlockProps to pass to the underlying CodeBlock component Examples Display a Complete File Extract Specific Lines You can extract specific lines from a file by adding a line reference to the URL and setting extractLines to true: Highlight Specific Lines You can highlight specific lines using the highlightLines prop: Launch Post // Detect dark theme var iframe = document.getElementById('tweet-1912033485285376492-240'); if (document.body.className.includes('dark-theme')) {

Apr 17, 2025 - 07:44
 0
FumaDocs React Component to Display Code from Github Repos

The GithubCodeBlock component allows you to embed and display code from GitHub repositories directly in your Fuma Docs application. It supports line extraction, syntax highlighting, and line highlighting features.

Installation

You need to have fumadocs setup ready and running

Step 1: Copy following code anywhere into your components

import * as Base from "fumadocs-ui/components/codeblock";
import { highlight } from "fumadocs-core/highlight";
import { transformerMetaHighlight } from "@shikijs/transformers";

// Types
export interface CodeBlockProps {
  code: string;
  wrapper?: Base.CodeBlockProps;
  lang: string;
  highlightLines?: string;
}

interface GithubCodeBlockProps {
  url: string;
  extractLines?: boolean;
  highlightLines?: string;
  wrapper?: Base.CodeBlockProps;
}

interface GitHubReference {
  rawUrl: string;
  fromLine?: number;
  toLine?: number;
  highlightLines?: string;
}

// Helper functions
function formatHighlightLines(highlightLines?: string): string | undefined {
  if (!highlightLines) return undefined;
  return highlightLines.startsWith("{") && highlightLines.endsWith("}")
    ? highlightLines
    : `{${highlightLines}}`;
}

function getLanguageFromUrl(url: string): string {
  try {
    return url.split(".").pop()?.toLowerCase() || "";
  } catch {
    return "";
  }
}

function parseGitHubUrl(url: string): GitHubReference {
  try {
    // Split the URL to separate the line reference part
    const [githubUrl, loc] = url.split("#");

    if (!githubUrl) {
      throw new Error("Invalid GitHub URL");
    }

    // Initialize line reference variables
    let fromLine: number | undefined;
    let toLine: number | undefined;
    let highlightLines: string | undefined;

    // Parse line references if present
    if (loc) {
      const lineParts = loc.split("-");

      if (lineParts[0]?.startsWith("L")) {
        fromLine = parseInt(lineParts[0].slice(1), 10) - 1;

        if (lineParts[1]?.startsWith("L")) {
          toLine = parseInt(lineParts[1].slice(1), 10) - 1;
        } else {
          toLine = fromLine;
        }

        // Always generate highlight lines from location
        // These will be used if no explicit highlightLines prop is provided
        if (fromLine !== undefined && toLine !== undefined) {
          const startLine = fromLine + 1;
          const endLine = toLine + 1;
          highlightLines =
            startLine === endLine
              ? `{${startLine}}`
              : `{${startLine}-${endLine}}`;
        }
      }
    }

    // Parse GitHub URL to create raw URL
    const urlObj = new URL(githubUrl);
    const pathParts = urlObj.pathname.split("/").slice(1);

    if (pathParts.length < 5) {
      throw new Error("Invalid GitHub repository path");
    }

    const [org, repo, _, branch, ...pathSeg] = pathParts;

    if (!org || !repo || !branch || pathSeg.length === 0) {
      throw new Error("Missing required GitHub path components");
    }

    // Create reference object with raw URL and line info
    return {
      rawUrl: `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join("/")}`,
      fromLine,
      toLine,
      highlightLines,
    };
  } catch (error) {
    console.error("Error parsing GitHub URL:", error);
    throw new Error(
      `Invalid GitHub URL: ${error instanceof Error ? error.message : String(error)}`
    );
  }
}

async function fetchCode(url: string, fromLine?: number, toLine?: number) {
  try {
    const response = await fetch(url, { cache: "force-cache" });

    if (!response.ok) {
      throw new Error(
        `Failed to fetch code: ${response.status} ${response.statusText}`
      );
    }

    const content = await response.text();

    // Return full content if no line numbers are specified
    if (fromLine === undefined || toLine === undefined) {
      return content;
    }

    // Extract specific lines
    const lines = content.split("\n");
    const selectedLines = lines.slice(fromLine, toLine + 1);

    if (selectedLines.length === 0) {
      return content;
    }

    // Calculate common indentation to remove
    const commonIndent = selectedLines.reduce(
      (indent: number, line: string) => {
        if (line.length === 0) return indent;
        const spaces = line.match(/^\s+/);
        return spaces ? Math.min(indent, spaces[0].length) : 0;
      },
      Infinity
    );

    // Remove common indentation and join lines
    return selectedLines
      .map((line) => {
        if (line.length === 0) return line;
        return line.slice(commonIndent < Infinity ? commonIndent : 0);
      })
      .join("\n");
  } catch (error) {
    console.error("Error fetching code:", error);
    return `// Error fetching code: ${error instanceof Error ? error.message : String(error)}`;
  }
}

// Components
export async function CodeBlock({
  code,
  lang,
  wrapper,
  highlightLines,
}: CodeBlockProps) {
  const rendered = await highlight(code, {
    lang,
    meta: highlightLines ? { __raw: highlightLines } : undefined,
    themes: {
      light: "github-light",
      dark: "github-dark",
    },
    components: {
      pre: Base.Pre,
    },
    transformers: [transformerMetaHighlight()],
  });

  return <Base.CodeBlock {...wrapper}>{rendered}Base.CodeBlock>;
}

export default async function GithubCodeBlock({
  url,
  extractLines = false,
  highlightLines,
  wrapper,
}: GithubCodeBlockProps) {
  try {
    // Validate GitHub URL
    if (!url.includes("github.com")) {
      throw new Error("This component only supports GitHub URLs");
    }

    // Parse GitHub URL to get raw URL and line info
    const reference = parseGitHubUrl(url);

    // Format highlight lines for Shiki
    // Priority: explicitly provided highlightLines prop > lines from URL loc
    const formattedHighlightLines = formatHighlightLines(
      highlightLines || reference.highlightLines
    );

    // Fetch the code content, extracting specific lines if needed
    const code = await fetchCode(
      reference.rawUrl,
      extractLines ? reference.fromLine : undefined,
      extractLines ? reference.toLine : undefined
    );

    const lang = getLanguageFromUrl(reference.rawUrl);

    return (
      <CodeBlock
        lang={lang}
        code={code}
        highlightLines={formattedHighlightLines}
        wrapper={wrapper}
      />
    );
  } catch (error) {
    console.error("Error in GithubCodeBlock:", error);
    return (
      <CodeBlock
        lang="text"
        code={`// Error: ${error instanceof Error ? error.message : String(error)}`}
        wrapper={wrapper}
      />
    );
  }
}

Step 2: Add to MDX Components

import defaultMdxComponents from "fumadocs-ui/mdx";
import type { MDXComponents } from "mdx/types";
import GithubCodeBlock from "./components/github-code-block";

export function getMDXComponents(components?: MDXComponents): MDXComponents {
  return {
    ...defaultMdxComponents,
    GithubCodeBlock: GithubCodeBlock,
    ...components,
  };
}

Basic Usage

<GithubCodeBlock url="https://github.com/rjvim/react-component-library-starter/blob/main/lerna.json" />

Props

The component accepts the following props:

Prop Type Default Description
url string (required) GitHub URL to the file you want to display
extractLines boolean false Whether to extract specific lines from the file
highlightLines string undefined Lines to highlight in the format "{1,3-4}"
wrapper object undefined CodeBlockProps to pass to the underlying CodeBlock component

Examples

Display a Complete File

<GithubCodeBlock url="https://github.com/rjvim/react-component-library-starter/blob/main/lerna.json" />

Extract Specific Lines

You can extract specific lines from a file by adding a line reference to the URL and setting extractLines to true:

<GithubCodeBlock
  url="https://github.com/rjvim/react-component-library-starter/blob/main/lerna.json#L2-L4"
  extractLines={true}
/>

Highlight Specific Lines

You can highlight specific lines using the highlightLines prop:

<GithubCodeBlock
  url="https://github.com/rjvim/react-component-library-starter/blob/main/lerna.json"
  highlightLines="{2,4}"
/>

Launch Post

// Detect dark theme var iframe = document.getElementById('tweet-1912033485285376492-240'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1912033485285376492&theme=dark" }

Note: In dev.to to editor I am not able to show the output of using the component, you can check that on: https://rjv.im/blog/solution/github-code-block