npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-file-preview-engine

v0.1.8

Published

A renderer-driven React file preview engine with extensible architecture for images, video, audio, pdf, html, and custom formats.

Readme

react-file-preview-engine

A renderer driven React file preview engine designed for extensibility, correctness, and long term maintainability.

react-file-preview-engine lets you preview files by delegating rendering to small, isolated renderers that decide if they can handle a file based on runtime context. It supports common media types out of the box and makes it trivial to add or override renderers for custom formats.

Why react-file-preview-engine

Inspired by @codesmith-99/react-file-preview and redesigned to address its architectural and maintenance limitations.

  • Renderer driven architecture instead of hard coded conditional rendering
  • Built in support for images, video, audio, pdf, html, and plain text
  • Automatic MIME type resolution using file name when needed
  • Supports multiple file source types including URL, File, Blob, and ArrayBuffer
  • Stable loading, ready, and error state handling
  • Abortable fetches with proper cleanup for fast file switching
  • First class support for custom renderers
  • Optional, fully typed additional render context
  • Pluggable error renderer
  • Fully typed public API
  • React is not bundled as a direct dependency
  • Actively maintained and designed for long term extensibility

Installation

# npm
npm install react-file-preview-engine

# yarn
yarn add react-file-preview-engine

# pnpm
pnpm add react-file-preview-engine

# bun
bun add react-file-preview-engine

Usage

react-file-preview-engine exposes a single default export, the <FilePreviewer /> component.

You can pass it a file source and basic file metadata. The source can be a URL, File, Blob, or ArrayBuffer. Using the provided MIME type or file name, the engine dynamically resolves the most suitable renderer at runtime.

Basic Usage

This is the minimal setup. The previewer automatically infers the MIME type from fileName if not provided.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  return <FilePreviewer src="https://example.com/sample.pdf" fileName="sample.pdf" />;
}

Previewing Local Files

You can preview files selected by the user without uploading them first. The engine automatically converts File, Blob, and ArrayBuffer sources to object URLs internally.

import React, { useState } from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  const [file, setFile] = useState<File>();

  return (
    <>
      <input type="file" onChange={(e) => setFile(e.target.files?.[0])} />
      {file && <FilePreviewer src={file} fileName={file.name} mimeType={file.type} />}
    </>
  );
}

Providing MIME Type Explicitly

If you already know the MIME type, you can pass it directly. This ensures the engine uses the correct renderer even when inference is not possible.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  return <FilePreviewer src={new Blob(["Hello world"], { type: "text/plain" })} mimeType="text/plain" fileName="hello.txt" />;
}

Handling Load and Error Events

You can listen to lifecycle events triggered by the active renderer.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  return (
    <FilePreviewer
      src="/document.pdf"
      fileName="document.pdf"
      onLoad={() => {
        console.log("File loaded");
      }}
      onError={() => {
        console.error("Failed to load file");
      }}
    />
  );
}

Auto Play Media Files

For audio and video files, you can enable auto play.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  return <FilePreviewer src="https://example.com/video.mp4" fileName="video.mp4" autoPlay={true} />;
}

Partial Customization

You can customize the loader, container props, and icon props without modifying any renderers.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

export default function App() {
  return (
    <FilePreviewer
      src="/image.jpg"
      fileName="image.jpg"
      loader={<div>Loading preview…</div>}
      containerProps={{ style: { border: "1px solid #e5e7eb", padding: 8 } }}
      iconProps={{ style: { fontSize: 48 } }}
    />
  );
}

Custom Error Renderer

When a renderer reports an error, the previewer switches to errorRenderer.

import React from "react";
import FilePreviewer from "react-file-preview-engine";

const errorRenderer = {
  Component() {
    return <div>Preview unavailable</div>;
  },
};

export default function App() {
  return <FilePreviewer src="/missing.pdf" fileName="missing.pdf" errorRenderer={errorRenderer} />;
}

Custom Renderers

react-file-preview-engine resolves previews using renderers. A renderer declares whether it can handle a file using canRender and renders the preview inside its Component.

Renderers receive a render context that includes src, mimeType, fileName, lifecycle callbacks, and any values passed via additionalContext. The same context mechanism applies to customRenderers and errorRenderer.

Renderer Resolution Order

When previewing a file, the engine checks renderers in this order:

  1. Your customRenderers (from first to last)
  2. Built-in default renderers
  3. fallbackRenderer (icon fallback)

This means you can override built-in renderers by providing a custom renderer with the same canRender logic.

Markdown Renderer Example

This example adds support for markdown files.

import React, { useEffect, useState } from "react";
import FilePreviewer from "react-file-preview-engine";
import type { Renderer } from "react-file-preview-engine/types";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
import { useRemark } from "react-remarkify";
import rehypeSanitize from "rehype-sanitize";

const markdownRenderer: Renderer = {
  name: "markdown",
  canRender({ mimeType }) {
    return mimeType === "text/markdown";
  },
  Component({ src, onLoad, onError }) {
    const [markdown, setMarkdown] = useState("");

    useEffect(() => {
      const controller = new AbortController();

      fetch(src, { signal: controller.signal })
        .then((res) => res.text())
        .then((text) => {
          setMarkdown(text);
          onLoad();
        })
        .catch(onError);

      return () => controller.abort();
    }, [src]);

    const reactContent = useRemark({
      markdown,
      remarkPlugins: [remarkGfm],
      rehypePlugins: [rehypeRaw, rehypeSanitize],
      remarkToRehypeOptions: { allowDangerousHtml: true },
    });

    return <div>{reactContent}</div>;
  },
};

export default function App() {
  return <FilePreviewer src="/README.md" fileName="README.md" customRenderers={[markdownRenderer]} />;
}

Passing Additional Context

You can extend renderers with custom configuration using additionalContext. This example enhances the markdown renderer to toggle between HTML and raw text rendering.

Important: additionalContext must remain stable across renders. Use useMemo for dynamic values or define it outside your component for static values.

import React, { useEffect, useMemo, useState } from "react";
import FilePreviewer from "react-file-preview-engine";
import type { Renderer } from "react-file-preview-engine/types";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
import { useRemark } from "react-remarkify";
import rehypeSanitize from "rehype-sanitize";

const markdownRenderer: Renderer<{ renderAsHtml?: boolean }> = {
  name: "markdown",
  canRender({ mimeType }) {
    return mimeType === "text/markdown";
  },
  Component({ src, onLoad, onError, renderAsHtml = true }) {
    const [markdown, setMarkdown] = useState("");

    useEffect(() => {
      const controller = new AbortController();

      fetch(src, { signal: controller.signal })
        .then((res) => res.text())
        .then((text) => {
          setMarkdown(text);
          onLoad();
        })
        .catch(onError);

      return () => controller.abort();
    }, [src]);

    const reactContent = useRemark({
      markdown,
      remarkPlugins: [remarkGfm],
      rehypePlugins: [rehypeRaw, rehypeSanitize],
      remarkToRehypeOptions: { allowDangerousHtml: true },
    });

    return renderAsHtml ? <div>{reactContent}</div> : <pre>{markdown}</pre>;
  },
};

export default function App() {
  const [renderAsHtml, setRenderAsHtml] = useState(true);
  const additionalContext = useMemo(() => ({ renderAsHtml }), [renderAsHtml]); // Keep stable across renders

  return (
    <>
      <button onClick={() => setRenderAsHtml(!renderAsHtml)}>Toggle {renderAsHtml ? "Raw" : "HTML"}</button>
      <FilePreviewer src="/README.md" fileName="README.md" customRenderers={[markdownRenderer]} additionalContext={additionalContext} />
    </>
  );
}

Default Renderers

The library includes built-in renderers for text, pdf, html, images, audio, and video. These handle common file types without any configuration.

You can explore the actual renderer definitions in the defaultRenderers constant on GitHub.

API Reference

FilePreviewer Component

Here is the full API for the <FilePreviewer> component, these properties can be set on an instance of FilePreviewer:

| Prop | Type | Required | Default | Description | | ------------------- | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | src | FileSource | Yes | – | Source URL of the file to preview | | mimeType | string | No | inferred | MIME type of the file | | fileName | string | No | - | Used for MIME inference and accessibility | | autoPlay | boolean | No | false | Auto play audio and video | | loader | ReactNode | No | <Loader /> | Shown while the file is loading | | customRenderers | Renderer[] | No | - | Additional or overriding renderers | | additionalContext | object | No | - | Extra data passed to the renderers. Must remain stable across renders | | errorRenderer | Renderer | No | fallbackRenderer | Renderer used on error | | containerProps | DivProps | No | - | Props applied to preview container | | iconProps | DivProps | No | - | Props applied to fallback icon | | onLoad | Eventhandler | No | – | Called when preview is ready | | onError | Eventhandler | No | – | Called when preview fails |

Types

DivProps

import type { DetailedHTMLProps, HTMLAttributes } from "react";

type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;

EventHandler

export type EventHandler = () => void;

FileSource

export type FileSource = string | File | Blob | ArrayBuffer;

Renderer

type RenderContext<T extends object = {}> = {
  src: string;
  mimeType: string;
  fileName: string;
  autoPlay: boolean;
  iconProps: DivProps;
  onLoad: () => void;
  onError: () => void;
} & T;
type Renderer<T extends object = {}> = {
  name?: string;
  canRender?(ctx: RenderContext<T>): boolean;
  Component(ctx: RenderContext<T>): JSX.Element;
};

License

This project is licensed under the MIT License.