---
title: "PDF redaction in JavaScript | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/samples/javascript-pdf-redaction/"
md_url: "https://www.nutrient.io/guides/web/samples/javascript-pdf-redaction.md"
last_updated: "2026-05-23T00:08:18.187Z"
description: "Discover a custom sidebar UI for automated content redaction. Preview results and use specific search options. Visit our JavaScript PDF library for more!"
---

# Redact PDFs using JavaScript

A custom sidebar UI to automate content redaction. Includes custom search options that only match specific data types, and a preview function to see redaction results before the redaction is applied to the PDF. Get additional resources by visiting our [JavaScript PDF redaction library](/guides/web/redaction.md).

[Get Started](https://www.nutrient.io/sdk/web/getting-started.md)

[All Samples](https://www.nutrient.io/guides/web/samples.md)

[Download](https://www.nutrient.io/guides/web/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```js

/*
 * In this example we enable the toolbar items for redactions
 * and add a custom sidebar from which a search criteria can
 * be used to create redaction annotations, and from where
 * users can preview and irreversibly apply redactions on
 * the document.
 */

import PSPDFKit from "@nutrient-sdk/viewer";
import React from "react";

import styles from "./styles";
import * as Icons from "./static/icons";

let instance = null;

export function load(defaultConfiguration) {
  return PSPDFKit.load({...defaultConfiguration,
    container: ".container",
    toolbarItems: [...PSPDFKit.defaultToolbarItems,
      { type: "redact-rectangle" },
      { type: "redact-text-highlighter" },
    ],
  }).then((_instance) => {
    console.log("Nutrient Web SDK successfully loaded!!", _instance);
    instance = _instance;

    return _instance;
  });
}

export const CustomContainer = React.forwardRef(() => {
  const [collapsed, setCollapsed] = React.useState(false);

  return (
    <>
      <style jsx>{styles}</style>
      <div className="container-wrapper">
        {
          // Custom overlapping sidebar
        }
        <div className={`sidebar ${collapsed? "sidebar-collapsed" : ""}`}>
          <div className="scroller">
            <header>
              <img src="/redaction/static/redaction.svg" alt="" />
              <h2>Content Redaction Options</h2>
              <p>
                Below you can see an implementation of Search & Redact
                functionality as well as the optional Redaction Preview toggle.
              </p>
            </header>
            <div className="section-header">
              <p>Search & Redact Tools</p>
            </div>
            <SearchSection />
            <div className="section-header">
              <p>Preview & Apply</p>
            </div>
            <PreviewSection />
          </div>
          <button
            className="collapse-handle"
            onClick={() => {
              setCollapsed((val) =>!val);
            }}
            aria-label={collapsed? "Expand" : "Collapse"}
            title={collapsed? "Expand" : "Collapse"}
          >
            <svg
              width="3"
              height="12"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path d="M1 0H0v12h1V0zM3 0H2v12h1V0z" fill="#848C9A" />

            </svg>
          </button>
        </div>
        {
          // Nutrient Web SDK container
        }
        <div className="container" />
      </div>
    </>
  );
});

const SearchSection = () => {
  const [searchType, setSearchType] = React.useState(PSPDFKit.SearchType.TEXT);

  const [searchPattern, setSearchPattern] = React.useState();
  const [searchInAnn, setSearchInAnn] = React.useState(true);

  React.useEffect(() => {
    if (searchType === PSPDFKit.SearchType.PRESET) {
      setSearchPattern(PSPDFKit.SearchPattern.CREDIT_CARD_NUMBER);
    } else {
      setSearchPattern("");
    }
  }, [searchType]);

  return (
    <>
      <style jsx>{styles}</style>
      <section className="section">
        <SearchTypeBar value={searchType} setter={setSearchType} />
        <label>
          <p>
            <strong>Search for:</strong>
          </p>
          {searchType === PSPDFKit.SearchType.PRESET? (
            <div>
              <PresetSelect value={searchPattern} setter={setSearchPattern} />
              <p>
                <small>
                  Verify the annotations created by applying a preset to discard
                  false positive results.{" "}
                  <a
                    href="https://www.nutrient.io/api/web/PSPDFKit.html#.SearchPattern"

                    target="_blank"
                    rel="noopener noreferrer"
                    aria-label="Learn more about search patterns"
                  >
                    Learn more
                  </a>.
                </small>
              </p>
            </div>
          ) : (
            <input
              id="search-pattern"
              type="text"
              className="search-input"
              onChange={(e) => setSearchPattern(e.target.value)}
            />
          )}
        </label>
        <div>
          <input
            type="checkbox"
            checked={searchInAnn}
            onChange={(e) => setSearchInAnn(e.target.checked)}
            id="search-in-annot-check"
          />
          <label htmlFor="search-in-annot-check">
            Search inside annotations
          </label>
        </div>
        <button
          onClick={async () => {
            if (!searchPattern) {
              return window.alert("Search pattern cannot be empty");
            }

            // This method will automatically create new redaction annotations
            const matches = await instance.createRedactionsBySearch(
              searchPattern,
              {
                searchType,
                searchInAnnotations: searchInAnn,
              }
            );

            if (!matches ||!matches.size) {
              return window.alert("No matches were found");
            }
          }}
          className="large-btn align-right mark-btn"
        >
          Mark for Redaction
        </button>
      </section>
    </>
  );
};

const PreviewSection = () => {
  const [isPreviewing, setIsPreviewing] = React.useState(false);

  React.useEffect(() => {
    if (instance) {
      // the "previewRedactionMode" flag will toggle between mark and redacted
      instance.setViewState((vs) =>
        vs.set("previewRedactionMode", isPreviewing)
      );
    }
  }, [isPreviewing]);

  const clearAnnotations = async () => {
    for (let i = 0; i < instance.totalPageCount; i++) {
      const anns = await instance.getAnnotations(i);
      const redactionAnns = anns.filter(
          (ann) => ann instanceof PSPDFKit.Annotations.RedactionAnnotation
        ).map((ann) => ann.id);

      instance.delete(redactionAnns);
    }
  };

  return (
    <>
      <style jsx>{styles}</style>
      <section className="preview-section">
        <div className="form-section-bar">
          <div
            className="form-section-desc"
            onClick={() => setIsPreviewing((val) =>!val)}
          >
            <p>
              <strong>Redaction Preview</strong>
            </p>
            <p>{isPreviewing? "On" : "Off"}</p>
          </div>
          <input
            type="checkbox"
            className="sr-only"
            checked={isPreviewing}
            onChange={(e) => setIsPreviewing(e.target.checked)}
            id="redaction-preview-input"
          />
          <label
            className={`img-btn ${isPreviewing? "btn-active" : ""}`}
            htmlFor="redaction-preview-input"
          >
            <span className="sr-only">Redaction preview</span>
            <Icons.RedactionPreview />
          </label>
        </div>
        <div className="btn-group confirm-btns">
          <button className="btn-plain" onClick={clearAnnotations}>
            Clear
          </button>
          <button
            className="btn-primary"
            onClick={() => {
              // This method will reload the current document with the
              // applied redactions.
              instance.applyRedactions();
            }}
          >
            Apply
          </button>
        </div>
      </section>
    </>
  );
};

const SearchTypeBar = (props) => {
  const { value, setter } = props;

  const searchTypesMap = {
    [PSPDFKit.SearchType.TEXT]: "Text",
    [PSPDFKit.SearchType.PRESET]: "Preset",
    [PSPDFKit.SearchType.REGEX]: "Regex",
  };

  return (
    <>
      <style jsx>{styles}</style>
      <fieldset>
        <legend className="sr-only">Search Type</legend>
        <div className="form-section-bar">
          <div className="form-section-desc">
            <p>
              <strong>Search Type</strong>
            </p>
            <p>{searchTypesMap[value]}</p>
          </div>
          <div className="btn-bar">
            <input
              type="radio"
              id="text-search-pattern"
              name="search-type"
              className="sr-only"
              checked={value === PSPDFKit.SearchType.TEXT}
              onChange={(e) => {
                if (e.target.checked) {
                  setter(PSPDFKit.SearchType.TEXT);
                }
              }}
            />
            <label
              className={`img-btn ${
                value === PSPDFKit.SearchType.TEXT? "btn-active" : ""
              }`}
              htmlFor="text-search-pattern"
            >
              <span className="sr-only">Text</span>
              <Icons.TextRedactionSearch />
            </label>

            <input
              type="radio"
              id="preset-search-pattern"
              name="search-type"
              className="sr-only"
              checked={value === PSPDFKit.SearchType.PRESET}
              onChange={(e) => {
                if (e.target.checked) {
                  setter(PSPDFKit.SearchType.PRESET);
                }
              }}
            />
            <label
              className={`img-btn ${
                value === PSPDFKit.SearchType.PRESET? "btn-active" : ""
              }`}
              htmlFor="preset-search-pattern"
            >
              <span className="sr-only">Preset</span>
              <Icons.PatternRedactionSearch />
            </label>
            <input
              type="radio"
              name="search-type"
              id="regex-search-pattern"
              className="sr-only"
              checked={value === PSPDFKit.SearchType.REGEX}
              onChange={(e) => {
                if (e.target.checked) {
                  setter(PSPDFKit.SearchType.REGEX);
                }
              }}
            />
            <label
              className={`img-btn ${
                value === PSPDFKit.SearchType.REGEX? "btn-active" : ""
              }`}
              htmlFor="regex-search-pattern"
            >
              <span className="sr-only">Regular expression</span>
              <Icons.RegexRedactionSearch />
            </label>
          </div>
        </div>
      </fieldset>
    </>
  );
};

const PresetSelect = (props) => {
  const { value, setter } = props;

  const { SearchPattern } = PSPDFKit;
  const presetsMap = {
    CREDIT_CARD_NUMBER: "Credit card number",
    DATE: "Date",
    TIME: "Time",
    EMAIL_ADDRESS: "E-mail address",
    INTERNATIONAL_PHONE_NUMBER: "International phone number",
    IP_V4: "IPv4 address",
    IP_V6: "IPv6 address",
    MAC_ADDRESS: "MAC address",
    NORTH_AMERICAN_PHONE_NUMBER: "North American phone number",
    SOCIAL_SECURITY_NUMBER: "Social Security number",
    URL: "URL",
    US_ZIP_CODE: "U.S. zip code",
    VIN: "VIN",
  };

  return (
    <>
      <style jsx>{styles}</style>
      <select
        value={value}
        onChange={(e) => setter(e.target.value)}
        id="search-pattern"
        className="search-input"
      >
        {Object.keys(SearchPattern).map((key) => (
          <option key={key} value={SearchPattern[key]}>
            {presetsMap[key]}
          </option>
        ))}
      </select>
    </>
  );
};

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Add electronic signature images to PDFs using JavaScript](/guides/web/samples/adding-image-electronic-signatures.md)
- [Open, view, and annotate on images using JavaScript](/guides/web/samples/annotating-images.md)
- [Customize PDF annotation permissions using JavaScript](/guides/web/samples/custom-annotation-permissions.md)
- [Customize PDF annotation tooltips using JavaScript](/guides/web/samples/custom-annotation-tooltip.md)
- [Add watermarks to PDFs using JavaScript example](/guides/web/samples/add-watermarks-to-pdf-javascript.md)
- [Customized Document Editor Toolbar](/guides/web/samples/customized-document-editor-toolbar.md)
- [Custom HTML PDF annotations using JavaScript](/guides/web/samples/custom-annotations.md)
- [View PDFs in dark mode using JavaScript](/guides/web/samples/dark-mode-pdf-viewer.md)
- [Edit PDFs using JavaScript](/guides/web/samples/edit-pdf-javascript.md)
- [Customizing PDF text search using JavaScript](/guides/web/samples/customized-pdf-search.md)
- [Create custom overlays on PDFs using JavaScript](/guides/web/samples/custom-overlay-items.md)
- [Add electronic signatures to PDFs using JavaScript](/guides/web/samples/electronic-signatures-in-pdf.md)
- [Customize the PDF toolbar using JavaScript](/guides/web/samples/customized-pdf-toolbar.md)
- [Open PDFs using JavaScript](/guides/web/samples/open-pdf-using-javascript.md)
- [PDF form support using JavaScript](/guides/web/samples/javascript-pdf-form.md)
- [Handling password-protected PDFs in our JavaScript viewer](/guides/web/samples/password-protected-pdf.md)
- [PDF presentation mode using JavaScript](/guides/web/samples/presentation-mode.md)
- [Disable PDF editing and annotations](/guides/web/samples/open-read-only-pdf.md)
- [PDF text selection using JavaScript](/guides/web/samples/pdf-text-selection-javascript.md)
- [Zoom example for our JavaScript PDF viewer](/guides/web/samples/zooming.md)
- [Customizing JavaScript PDF printing modes](/guides/web/samples/pdf-printing-modes.md)
- [Storing electronic signatures in the browser using JavaScript](/guides/web/samples/stored-electronic-signatures.md)
- [Flipbook PDF viewer using JavaScript](/guides/web/samples/flipbook.md)
- [Collaborate on PDFs using JavaScript](/guides/web/samples/instant-pdf-collaboration.md)
- [JavaScript PDF magazine viewer](/guides/web/samples/javascript-magazine-viewer.md)
- [Hide or reveal area on PDFs using JavaScript](/guides/web/samples/hide-reveal-area-in-pdf.md)
- [PDF annotation in JavaScript](/guides/web/samples/javascript-pdf-annotations.md)
- [Digitally sign a PDF using JavaScript](/guides/web/samples/javascript-digital-signatures.md)
- [PDF Collaboration permissions using JavaScript](/guides/web/samples/collaboration-permissions.md)
- [Drag-and-drop UI in our JavaScript PDF viewer](/guides/web/samples/drag-and-drop.md)
- [Customize the UI for PDF annotations using JavaScript](/guides/web/samples/annotations-inspector.md)

