Set Character Formatting in Word with JavaScript in React

2026-10-16 07:59:55 Written by  Amy Zhao
Rate this item
(0 votes)

Character formatting decides what text looks like on the page — which font it uses, how large it is, what color it is, and whether it is bold, slanted, underlined or struck through. In Word's Open XML structure these properties hang off the run, not the paragraph: every run in a sentence can carry a set of its own. Spire.Doc for JavaScript maps that structure onto the TextRange.CharacterFormat object and reads and writes it directly in the browser via WebAssembly, with no backend server required.

This article covers two core features:

For installation and project setup, refer to Integrating Spire.Doc for JavaScript in a React Project. The examples below assume Spire.Doc is installed and the WebAssembly module is initialized.


Set Character Formatting

After Document.AddSection() creates a section, section.AddParagraph() gives you a paragraph and paragraph.AppendText() appends text to it — the return value of AppendText is a TextRange object, and once you hold it you can set CharacterFormat on it directly. To break the line without starting a new paragraph, call paragraph.AppendBreak(wasmModule.BreakType.LineBreak).

The sample below walks through the common character formats one by one. Each line of text changes exactly one property, so the effect can be read straight off the result. One line is the exception: the font-name example deliberately mixes a Chinese word into its text, because only East Asian characters are read from the Far-East font slot that the line sets.

function App() {
  const CharacterFormatting = async () => {
    const docModule = window.wasmModule?.spiredoc;
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Create the document and the section
    let doc = new docModule.Document();
    let sec = doc.AddSection();

    // The title paragraph takes the built-in "Title" style
    let titleParagraph = sec.AddParagraph();
    titleParagraph.AppendText("Character Formatting Overview");
    titleParagraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Title });

    let paragraph = sec.AddParagraph();

    // Strikeout
    let tr = paragraph.AppendText("Strikethough Text");
    tr.CharacterFormat.IsStrikeout = true;

    // Shadow
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Shadow Text");
    tr.CharacterFormat.IsShadow = true;

    // Small caps
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Small caps Text");
    tr.CharacterFormat.IsSmallCaps = true;

    // Double strikeout
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Double Strikethough Text");
    tr.CharacterFormat.DoubleStrike = true;

    // Outline
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Outline Text");
    tr.CharacterFormat.IsOutLine = true;

    // All caps
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("AllCaps Text");
    tr.CharacterFormat.AllCaps = true;

    // Subscript and superscript
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Text");
    tr = paragraph.AppendText("SubScript");
    tr.CharacterFormat.SubSuperScript = docModule.SubSuperScript.SubScript;
    tr = paragraph.AppendText("And");
    tr = paragraph.AppendText("SuperScript");
    tr.CharacterFormat.SubSuperScript = docModule.SubSuperScript.SuperScript;

    // Emboss, with a white text color so the effect shows up better
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Emboss Text");
    tr.CharacterFormat.Emboss = true;
    tr.CharacterFormat.TextColor = docModule.Color.get_White();

    // Hidden text
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Hidden:");
    tr = paragraph.AppendText("Hidden Text");
    tr.CharacterFormat.Hidden = true;

    // Engrave
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Engrave Text");
    tr.CharacterFormat.Engrave = true;
    tr.CharacterFormat.TextColor = docModule.Color.get_White();

    // The Western, non-Far-East and Far-East font names are set separately
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("WesternFonts中文字体");
    tr.CharacterFormat.FontNameAscii = "Calibri";
    tr.CharacterFormat.FontNameNonFarEast = "Calibri";
    tr.CharacterFormat.FontNameFarEast = "Simsun";

    // Font size
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Font Size");
    tr.CharacterFormat.FontSize = 20;

    // Font color
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Font Color");
    tr.CharacterFormat.TextColor = docModule.Color.get_Red();

    // Bold + italic
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Bold Italic Text");
    tr.CharacterFormat.Bold = true;
    tr.CharacterFormat.Italic = true;

    // Underline
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Underline Style");
    tr.CharacterFormat.UnderlineStyle = docModule.UnderlineStyle.Single;

    // Highlight (background)
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Highlight Text");
    tr.CharacterFormat.HighlightColor = docModule.Color.get_Yellow();

    // Character shading
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Text has shading");
    tr.CharacterFormat.TextBackgroundColor = docModule.Color.get_Green();

    // Border around the characters
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Border Around Text");
    tr.CharacterFormat.Border.BorderType = docModule.BorderStyle.Single;

    // Character scaling at 150%
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Text Scale");
    tr.CharacterFormat.TextScale = 150;

    // Character spacing of 2 points
    paragraph.AppendBreak(docModule.BreakType.LineBreak);
    tr = paragraph.AppendText("Character Spacing is 2 point");
    tr.CharacterFormat.CharacterSpacing = 2;

    // Define the output file name
    const outputFileName = "CharacterFormatting-result.docx";

    // Save the document to the given path
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
    // Release resources
    doc.Dispose();

    // Read the saved file back and wrap it as a Blob
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"});
    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 Various Character Formats</h1>
      <button onClick={CharacterFormatting}>Generate</button>
    </div>
  );
}
export default App;

Every line of the generated document shows the matching character effect, and can be compared with the code line by line

The result after setting various character formats


Apply Several Character Formats in One Paragraph

One paragraph can hold several TextRange objects, and each of them has its own CharacterFormat. That means layouts such as "the first half in bold blue, the second half back at a regular size" do not need to be split into two paragraphs — just call AppendText again; the format only applies to the text appended by that one call.

function App() {
  const MultiStylesInAParagraph = async () => {
    const docModule = window.wasmModule?.spiredoc;
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Create the document and the section
    let doc = new docModule.Document();
    let section = doc.AddSection();

    // Add a new paragraph
    let para = section.AddParagraph();

    // The first TextRange: Calibri 16 pt, blue, bold, single underline
    let range = para.AppendText("Quarterly Delivery Note ");
    range.CharacterFormat.FontName = "Calibri";
    range.CharacterFormat.FontSize = 16;
    range.CharacterFormat.TextColor = docModule.Color.get_Blue();
    range.CharacterFormat.Bold = true;
    range.CharacterFormat.UnderlineStyle = docModule.UnderlineStyle.Single;

    // The second TextRange: still the same paragraph, now Calibri 15 pt regular
    range = para.AppendText("This delivery covers three business areas, and acceptance is based on the result of the online trial run");
    range.CharacterFormat.FontName = "Calibri";
    range.CharacterFormat.FontSize = 15;

    // Define the output file name
    const outputFileName = "MultiStylesInAParagraph-result.docx";

    // Save the document to the given path
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
    // Release resources
    doc.Dispose();

    // Read the saved file back and wrap it as a Blob
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"});
    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>Apply Multiple Character Formats in One Paragraph</h1>
      <button onClick={MultiStylesInAParagraph}>Generate</button>
    </div>
  );
}
export default App;

The first half of the paragraph is bold, blue and underlined; the second half is back to a regular weight

The result of mixing character formats inside one paragraph


FAQ

FontName is set, but the Chinese text does not change

Cause: CharacterFormat.FontName only writes to the Western (ascii/hAnsi) font slots, while Chinese characters are taken from the separate "East Asian" slot. The two are stored independently, so setting one leaves the other exactly as it was.

Solution: Set the font used by each script separately — FontNameAscii / FontNameNonFarEast for the Western text, FontNameFarEast for the Chinese:

tr.CharacterFormat.FontNameAscii = "Calibri";
tr.CharacterFormat.FontNameNonFarEast = "Calibri";
tr.CharacterFormat.FontNameFarEast = "Simsun";

Emboss and Engrave show no visible effect

Cause: Both effects rely on a light-and-shadow contrast, and the default black text on a white background has almost no visual difference to work with.

Solution: Set the text color to white, so that the characters are shaped by their highlight and shadow alone:

tr.CharacterFormat.Emboss = true;
tr.CharacterFormat.TextColor = wasmModule.Color.get_White();

The downloaded Word document cannot be opened, or is reported as corrupted

Cause: The MIME type was wrong when the Blob was created, so the browser cannot identify the file format correctly.

Solution: Make sure the exact docx MIME type is used:

const modifiedFile = new Blob([modifiedFileArray], {
  type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});

Get a Free License

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