A table has only a few seconds to be understood, and the work is done not only by the numbers but by the fonts: a title big enough to stand out, a figure that matters found at a glance, a cancelled line spotted immediately. In Excel every one of those differences is carried by a font object belonging to a single cell -- font name, size, colour, bold, italic, underline, strikethrough; changing a cell touches only that cell. One cell can also hold several fonts at once, and switching a single word to another colour or size lifts it out of the sentence around it. Spire.XLS for JavaScript performs these operations in the browser through WebAssembly; the output file is managed by a virtual file system (VFS), with no backend service required.

This article covers two feature points:

For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialized.


Set the font formatting of a cell

Every cell carries a font object of its own, and all seven properties -- font name, size, colour, bold, italic, underline and strikethrough -- hang off that object. To see what each one does, start a worksheet of its own, write the property's name and a sample of text row by row, and set the matching property on the cell that holds the sample: a change lands on that cell alone, and the description in column A keeps its own look. The steps are:

  1. Load the font file into the VFS with window.spire.FetchFileToVFS.
  2. Create a workbook with new Workbook() and take the first worksheet with workbook.Worksheets.get(0).
  3. Write the properties out one per row with sheet.Range.get: the name into column A and the sample text into column B, rows starting at 1 and going up by 2.
  4. Set the matching format on each row's sample through FontName, Size, Color, IsBold, IsItalic, Underline and IsStrikethrough on Range.Style.Font, taking the font colour from xlsModule.Color.get_Red() and the underline from xlsModule.FontUnderlineType.Single.
  5. Set both columns to a width of 25 with sheet.Columns.get(0).ColumnWidth and sheet.Columns.get(1).ColumnWidth.
  6. Save the workbook with workbook.SaveToFile and dispose of it with workbook.Dispose to free resources.

The full code example below shows how to set font formatting for cells in React:

function App() {
  const setCellFont = async () => {
    // get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // check that the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // load the font file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // create a new workbook and take the first worksheet
    const workbook = new xlsModule.Workbook();
    const sheet = workbook.Worksheets.get(0);

    // set the font name
    let row = 1;
    sheet.Range.get(`A${row}`).Value = 'Font name';
    sheet.Range.get(`B${row}`).Value = 'Arial';
    sheet.Range.get(`B${row}`).Style.Font.FontName = 'Arial';

    // set the font size
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Font size';
    sheet.Range.get(`B${row}`).Value = '15';
    sheet.Range.get(`B${row}`).Style.Font.Size = 15;

    // set the font colour
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Font colour';
    sheet.Range.get(`B${row}`).Value = 'Red';
    sheet.Range.get(`B${row}`).Style.Font.Color = xlsModule.Color.get_Red();

    // bold the text
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Bold';
    sheet.Range.get(`B${row}`).Value = 'Bold';
    sheet.Range.get(`B${row}`).Style.Font.IsBold = true;

    // italicise the text
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Italic';
    sheet.Range.get(`B${row}`).Value = 'Italic';
    sheet.Range.get(`B${row}`).Style.Font.IsItalic = true;

    // underline the text
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Underline';
    sheet.Range.get(`B${row}`).Value = 'Underline';
    sheet.Range.get(`B${row}`).Style.Font.Underline = xlsModule.FontUnderlineType.Single;

    // strike through the text
    row += 2;
    sheet.Range.get(`A${row}`).Value = 'Strikethrough';
    sheet.Range.get(`B${row}`).Value = 'Strikethrough';
    sheet.Range.get(`B${row}`).Style.Font.IsStrikethrough = true;

    // set the column widths
    sheet.Columns.get(0).ColumnWidth = 25;
    sheet.Columns.get(1).ColumnWidth = 25;

    // save the workbook as an Excel file
    const outputFileName = 'CellFont.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2016 });

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Set Cell Font Formatting</h1>
      <button id="cell-font" onClick={setCellFont}>Set the font formatting of a cell</button>
    </div>
  );
}

export default App;

After running, the effect of setting font formatting for individual cells:

Font formatting applied to cells


Mix several fonts inside one cell

A cell's rich text object lets one run of text be cut at character positions and each piece given a different font, while the sentence still reads as a whole. The way to do it is to create the font objects first and then assign them range by range with SetFont -- each call overwrites one range, so every part of the sentence has to be covered. Ranges count from 0 and include both ends. The steps are:

  1. Load the font file into the VFS with window.spire.FetchFileToVFS.
  2. Create a workbook with new Workbook() and take the first worksheet with workbook.Worksheets.get(0).
  3. Create two fonts with workbook.CreateFont(): one for the whole sentence, and one that emphasises the key phrase through IsBold and KnownColor.
  4. Take the cell that holds the sentence with sheet.Range.get('A1'), and write the whole sentence into its rich text object through RichText.Text.
  5. Work out the start and end of the text that needs the new font within the sentence with note.indexOf(key) and key.length, then assign the fonts to the three parts -- before the key phrase, the key phrase itself and after it -- with RichText.SetFont.
  6. Save the workbook with workbook.SaveToFile and dispose of it with workbook.Dispose to free resources.

The full code example below shows how to give part of the text in one cell a different font in React:

function App() {
  const setRichTextFonts = async () => {
    // get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // check that the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // load the font file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // create a new workbook and take the first worksheet
    const workbook = new xlsModule.Workbook();
    const sheet = workbook.Worksheets.get(0);

    // create the first font, for the whole sentence
    const font1 = workbook.CreateFont();
    font1.FontName = 'Arial';
    font1.Size = 12;

    // create the second font, for the key phrase
    const font2 = workbook.CreateFont();
    font2.FontName = 'Arial';
    font2.Size = 14;
    font2.IsBold = true;
    font2.KnownColor = xlsModule.ExcelColors.Red;

    // take the cell's rich text object and write the whole sentence
    const note = 'This quotation is valid for 30 days; contact your sales representative to extend it.';
    const key = '30 days';
    const richText = sheet.Range.get('A1').RichText;
    richText.Text = note;

    // locate the character range the key phrase occupies
    const start = note.indexOf(key);
    const end = start + key.length - 1;

    // set the part before the key phrase to the first font
    richText.SetFont(0, start - 1, font1);

    // set the key phrase itself to the second font
    richText.SetFont(start, end, font2);

    // keep the part after the key phrase in the first font
    richText.SetFont(end + 1, note.length - 1, font1);

    // save the workbook as an Excel file
    const outputFileName = 'RichTextFont.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2016 });

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Mix Several Fonts Inside One Cell</h1>
      <button id="rich-text-fonts" onClick={setRichTextFonts}>Give part of the text a different font</button>
    </div>
  );
}

export default App;

After running, the effect of mixing several fonts inside one cell:

Two fonts mixed inside one cell


FAQ

What value should SetFont's end position take

Reason: Both position arguments of SetFont count from 0 and include the end position itself, so passing a string's length directly lands one character past the end.

Solution: Pass "length minus one" as the end position. To cover a whole run of text, use the sentence's length minus one:

richText.SetFont(0, note.length - 1, font1);

Get a Free License

Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.

An Excel comment usually carries a paragraph of text, explaining a number or adding a note. When the thing to be explained is itself a picture -- a supplier mark, a product photo, a sketch of a part -- text alone will not do. Spire.XLS for JavaScript can fill a comment's background with a picture, so the image appears beside the cell without a separate floating picture object being placed on the sheet. A comment's background is controlled by its fill object, and switching to a solid colour likewise changes only that one object. Spire.XLS for JavaScript performs these operations in the browser through WebAssembly; input and output files are managed by a virtual file system (VFS), with no backend service required.

This article covers two feature points:

For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialized.


Insert a picture comment into a cell

A comment is attached to a cell; giving one a picture means first obtaining the comment object on the target cell and then filling it. The picture becomes the comment box's background, replacing the default pale-yellow shading, and it is this picture that appears when the mouse moves over the cell or the file is opened. The picture is scaled to the size of the comment box, and the default box is a flat rectangle, so a square picture is stretched out of shape; after filling, the width and height must therefore be set so that the box matches the picture's proportions. Where the box sits on the sheet is decided by a separate pair of position properties, so it does not have to follow the cell border. The steps are:

  1. Load the font, the picture and the test data file into the VFS.
  2. Load the workbook with workbook.LoadFromFile.
  3. Take the cell the comment will be attached to with sheet.Range.get('A4').
  4. Create a comment object on the cell with range.AddComment().
  5. Fill the comment background with the picture using comment.Fill.CustomPicture, passing the picture as a stream built by new xlsModule.Stream('logo.png') and 'None' for the name argument.
  6. Set comment.Width and comment.Height so the comment box is square, matching the square picture, which keeps the picture from being stretched.
  7. Place the comment box relative to the top-left corner of the worksheet with comment.Top and comment.Left, so that it covers the content below without obscuring its own row.
  8. Set comment.Visible to show the comment as soon as the file is opened.
  9. Save the workbook with workbook.SaveToFile.
  10. Dispose of the workbook with workbook.Dispose to free resources.

The complete code example below shows how to insert a picture comment into an Excel cell in React:

function App() {
  const addPictureComment = async () => {
    // get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // check that the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // load the font, the picture and the test data file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    await window.spire.FetchFileToVFS('logo.png', '', `${process.env.PUBLIC_URL}data/`);
    const inputFileName = 'ProductList.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // take the first worksheet and add a comment to cell A4, filled with the picture
    const sheet = workbook.Worksheets.get(0);
    const range = sheet.Range.get('A4');
    const comment = range.AddComment();
    comment.Fill.CustomPicture({ im: new xlsModule.Stream('logo.png'), name: 'None' });

    // set the width and height of the comment box
    comment.Width = 150;
    comment.Height = 150;

    // place the comment box relative to the top-left corner of the worksheet
    comment.Top = 100;
    comment.Left = 400;

    // make the comment show as soon as the file is opened
    comment.Visible = true;

    // save the workbook
    const outputFileName = 'PictureComment.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Insert Comments with Pictures</h1>
      <button id="picture-comment" onClick={addPictureComment}>Insert a picture comment into a cell</button>
    </div>
  );
}

export default App;

After running, the effect of inserting a picture comment into a cell:

Picture comment inserted into a cell


Fill a comment with a solid colour

A comment background need not be a picture. When all that is needed is for one comment to stand out from the pale-yellow shading around it, specifying a solid colour is more straightforward than preparing an image. Filling with a picture and filling with a solid colour use the same comment.Fill object; only the fill type changes from picture to solid. The steps are:

  1. Load the font and the test data file into the VFS.
  2. Load the workbook with workbook.LoadFromFile.
  3. Take the cell the comment will be attached to with sheet.Range.get('A4') and create the comment with range.AddComment().
  4. Write the comment text with comment.Text.
  5. Create a font with workbook.CreateFont() and set the whole text to it with comment.RichText.SetFont.
  6. Set comment.Fill.FillType to the solid fill type, xlsModule.ShapeFillType.SolidColor.
  7. Pick the colour with comment.Fill.ForeColor.
  8. Set comment.Visible to show the comment as soon as the file is opened.
  9. Save the workbook with workbook.SaveToFile.
  10. Dispose of the workbook with workbook.Dispose to free resources.

The complete code example below shows how to fill an Excel comment with a solid colour in React:

function App() {
  const fillCommentColor = async () => {
    // get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // check that the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // load the font and the test data file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'ProductList.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // take the first worksheet and add a comment to cell A4
    const sheet = workbook.Worksheets.get(0);
    const range = sheet.Range.get('A4');

    // create the font the comment text will use
    const font = workbook.CreateFont();
    font.FontName = 'Arial';
    font.Size = 11;
    font.KnownColor = xlsModule.ExcelColors.Orange;

    // write the comment text and set the whole text to that font
    const commentText = 'This product leads the season';
    range.Comment.Text = commentText;
    range.Comment.RichText.SetFont(0, commentText.length - 1, font);

    // set the comment fill to a solid colour and pick the colour
    range.Comment.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
    range.Comment.Fill.ForeColor = xlsModule.Color.get_SkyBlue();
    range.Comment.Visible = true;

    // save the workbook
    const outputFileName = 'CommentFillColor.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Insert Comments with Pictures</h1>
      <button id="comment-fill-color" onClick={fillCommentColor}>Fill a comment with a solid colour</button>
    </div>
  );
}

export default App;

After running, the effect of filling a comment with a solid colour:

Comment filled with a solid colour


FAQ

Why does the picture comment not appear when the result file is opened

Reason: Comments are hidden by default and appear only when the mouse moves over the cell. If the comment was not set to visible before saving, reopening the file shows an ordinary worksheet, and the picture comment does not appear on its own.

Solution: Set comment.Visible to true, and the comment appears as soon as the file is opened:

comment.Visible = true;

Get a Free License

Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.

Hyperlinks in a PDF are meant to save work: one click and you are there, no copying an address, no retyping it. The catch is that they are rarely there when you need them. A brand-new document should come with its download page, a contact address and a product link already in place. An older, already laid-out document should send the product name recurring in its body to the same introduction page. Doing it by hand means dragging a selection and pasting an address at every spot — and on a long document that never ends.

Moving the job into the browser is what Spire.PDF for JavaScript is for: it loads, modifies and saves PDF documents directly on WebAssembly, with PdfTextWebLink drawing visible link text in one step and PdfFileLinkAnnotation attaching a document link. Everything runs locally, reading and writing files through a virtual file system (VFS) with no backend involved.

This article covers two core tasks:

For installation and project setup, see Integrate Spire.PDF for JavaScript in a React project. The example below assumes Spire.PDF is installed and the WebAssembly module is initialized.


Add Hyperlinks to a PDF

When you build a document from scratch, everything on the page is decided by code, and links fall into a few kinds:

  • Simple text link: the URL drawn as ordinary text, with no annotation attached; whether it is clickable is up to the viewer — Chrome and others auto-detect the URL and make it clickable — so it is here only for contrast with the explicitly linked ones.
  • Hypertext link: PdfTextWebLink with Text, Url, Font and Brush set; DrawTextWebLink() draws the underlined link text in one step.
  • Document link: PdfFileLinkAnnotation(hotspot rectangle, target file), with the rectangle defined by you.
function App() {
  const addLinksToNewPdf = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check that the module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Drawing text needs a font; load it into the VFS first
    const fontVfs = '/Library/Fonts/ARIAL UNICODE MS.TTF';
    await window.spire.FetchFileToVFS('ARIAL UNICODE MS.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // Create a blank document
    const doc = new pdfModule.PdfDocument();

    // Add a section and set its margins to 0: coordinates then equal page coordinates
    const section = doc.Sections.Add();
    section.PageSettings.Size = pdfModule.PdfPageSize.A4();
    const margins = new pdfModule.PdfMargins();
    margins.Top = 0;
    margins.Bottom = 0;
    margins.Left = 0;
    margins.Right = 0;
    section.PageSettings.Margins = margins;

    const page = section.Pages.Add();

    const font = new pdfModule.PdfTrueTypeFont({ fontFile: fontVfs, size: 13 });
    const linkFont = new pdfModule.PdfTrueTypeFont({ fontFile: fontVfs, size: 13, style: pdfModule.PdfFontStyle.Underline });
    const format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Left });

    // Draw a plain line of text as a label
    const drawLabel = (text, y) => {
      page.Canvas.DrawString({
        s: text, font: font, brush: pdfModule.PdfBrushes.get_Black(), x: 60, y: y, format: format,
      });
    };

    // Draw a line of underlined text and hand back its rectangle as the hotspot
    const drawLinkText = (text, y) => {
      const size = linkFont.MeasureString({ text: text });
      page.Canvas.DrawString({
        s: text, font: linkFont, brush: pdfModule.PdfBrushes.get_Blue(), x: 160, y: y, format: format,
      });
      return new pdfModule.RectangleF({ x: 160, y: y, width: size.Width, height: size.Height });
    };

    const url = 'https://www.e-iceblue.com/Introduce/pdf-for-javascript.html';

    // 1) Simple text link: just the URL drawn as ordinary text, with no annotation attached (clickability depends on the viewer)
    let y = 80;
    drawLabel('Simple text link:', y);
    drawLinkText(url, y);

    // 2) Hypertext link: DrawTextWebLink draws the text and attaches the link in one step
    y += 34;
    drawLabel('Hypertext link:', y);
    const webLink = new pdfModule.PdfTextWebLink();
    webLink.Text = 'Visit our site';
    webLink.Url = url;
    webLink.Font = linkFont;
    webLink.Brush = pdfModule.PdfBrushes.get_Blue();
    webLink.DrawTextWebLink({ graphics: page.Canvas, location: new pdfModule.PointF(160, y) });

    // 3) Email link: same class, with a mailto: URL
    y += 34;
    drawLabel('Email link:', y);
    const mailLink = new pdfModule.PdfTextWebLink();
    mailLink.Text = 'Contact support';
    mailLink.Url = 'mailto:support@e-iceblue.com';
    mailLink.Font = linkFont;
    mailLink.Brush = pdfModule.PdfBrushes.get_Blue();
    mailLink.DrawTextWebLink({ graphics: page.Canvas, location: new pdfModule.PointF(160, y) });

    // 4) Document link: hotspot rectangle + target file
    y += 34;
    drawLabel('Document link:', y);
    const fileName = 'Report.xlsx';
    const fileBounds = drawLinkText('Open file', y);
    page.Annotations.Add(new pdfModule.PdfFileLinkAnnotation(fileBounds, fileName));

    // Save the result document
    const outputFileName = 'HyperlinkSample.pdf';
    doc.SaveToFile(outputFileName);
    doc.Close();

    // Read the generated file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/pdf' });
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(downloadUrl);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Add Hyperlinks</h1>
      <button onClick={addLinksToNewPdf}>
        Start Creating
      </button>
    </div>
  );
}

export default App;

All four links — simple text, hypertext, email and document — are in place in the new document:

All four links — simple text, hypertext, email and document — are in place in the new document


Add Hyperlinks to Text

To add links to an existing document, work the other way round: find the position in the document first, then lay the link over it. PdfTextFinder searches the text of a given page by keyword, and each match carries a bounding rectangle. Build a PdfUriAnnotation from it and add it to the page annotation collection, and the link lands exactly on the original text instead of you doing the measuring.

function App() {
  const addHyperlinksToText = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check that the module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the PDF to be processed into the VFS
    const inputFileName = 'ProductManual.pdf';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create a PdfDocument object and load the PDF
    let doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // Take the first page
    const page = doc.Pages.get_Item(0);

    // Search the page for the keyword; Parameter is case-sensitive by default, so switch to IgnoreCase
    const finder = new pdfModule.PdfTextFinder(page);
    finder.Options.Parameter = pdfModule.TextFindParameter.IgnoreCase;
    const finds = finder.Find('Aurora');

    // Create one link annotation for each match
    const linkUrl = 'https://www.e-iceblue.com/Introduce/pdf-for-javascript.html';
    for (let i = 0; i < finds.length; i++) {
      // The bounding rectangle of a match is the link hotspot
      const annotation = new pdfModule.PdfUriAnnotation({ rectangle: finds.get(i).Bounds[0] });
      annotation.Uri = linkUrl;

      // Attach the annotation to the page annotation collection
      page.Annotations.Add(annotation);
    }

    // Save the result document
    const outputFileName = 'HyperlinksAdded.pdf';
    doc.SaveToFile(outputFileName);
    doc.Close();

    // Read the generated file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/pdf' });
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(downloadUrl);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Add Hyperlinks to Text</h1>
      <button onClick={addHyperlinksToText}>
        Start Adding
      </button>
    </div>
  );
}

export default App;

All three occurrences of Aurora now carry a hyperlink:

All three occurrences of Aurora now carry a hyperlink


FAQ

Find() returns nothing even though the word is right there in the text

Cause: Options.Parameter defaults to TextFindParameter.None, which is case-sensitive, so searching for aurora will not match the capitalised Aurora; and the finder searches only the single page it was constructed with.

Fix: set it to IgnoreCase; to search the whole document, build one finder per page:

finder.Options.Parameter = pdfModule.TextFindParameter.IgnoreCase;

Measured: Aurora appears three times on page 1, and a case-sensitive search returns 0.

The link is there, but nothing shows up when the file is opened

Cause: this kind of link annotation is only a click hotspot — Spire generates no appearance stream (/AP) for it, and neither Chrome (PDFium) nor PyMuPDF (mupdf) draws a border for it; setting Border/Color only writes into the annotation dictionary (/Border [0 0 1], /C [0 0 1]) and stays invisible on the page.

Fix: the link is still clickable. In task 1 the hypertext, email, simple-text and document links all have their text drawn by the code, so they are visible to begin with; for a hotspot laid over existing text in task 2, do not rely on the annotation border — draw an underline at the link position with page.Canvas.DrawString().


Get a Free License

If you want to remove the evaluation message from the result document, or get past the feature limits, contact our sales team for a temporary 30-day license.

Page 8 of 371
page 8