Styles are the way Word reuses formatting: give a set of formatting — the font, the size, the colour, the paragraph spacing — a name and save it, and from then on every paragraph that carries that style name picks the whole set up automatically. Change the style definition and every paragraph that references it updates along with it, which is exactly what setting the formatting on a paragraph directly cannot do. Spire.Doc for JavaScript performs all of this in the browser via WebAssembly, using a virtual file system (VFS) to manage input and output files — no backend server required.
Structurally a paragraph style holds two parts at once: character formatting and paragraph formatting. Once a built-in style has been taken, ParagraphStyle.CharacterFormat changes the text-level properties and ParagraphStyle.ParagraphFormat changes the paragraph-level ones. The library maps this model onto the Document.Styles collection in full.
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.
Modify the Built-in Styles
Word ships with a batch of built-in styles — Title, Normal, Heading 1 to Heading 9 and so on. document.AddStyle({ builtinStyle }) takes the named built-in style (creating it if it does not exist yet) and returns its object, and once you have it, it can be rewritten.
Note that the return type of AddStyle is the generic Style, so before changing the paragraph format you have to confirm that the object really is a paragraph style — instanceof wasmModule.ParagraphStyle is the check. Normal is the base style of the body text, and changing it also affects every style that inherits from it, so it is usually used only to unify the body font and the font size.
function App() {
const Styles = async () => {
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
await window.spire.FetchFileToVFS("ARIALUNI.TTF", "/Library/Fonts/", `${process.env.PUBLIC_URL}static/font/`);
// Create the document and the section
let doc = new docModule.Document();
let sec = doc.AddSection();
// Take the built-in Title style and rewrite it with a custom colour scheme:
// a bottom border and left alignment
let titleStyle = doc.AddStyle({ builtinStyle: docModule.BuiltinStyle.Title });
// Check whether it is a paragraph style; if it is, set the paragraph format too
if (titleStyle instanceof docModule.ParagraphStyle) {
let ps = titleStyle;
ps.CharacterFormat.FontName = "Arial Unicode MS";
ps.CharacterFormat.FontSize = 28;
ps.CharacterFormat.TextColor = docModule.Color.FromArgb(42, 123, 136);
ps.ParagraphFormat.Borders.Bottom.BorderType = docModule.BorderStyle.Single;
ps.ParagraphFormat.Borders.Bottom.Color = docModule.Color.FromArgb(42, 123, 136);
ps.ParagraphFormat.Borders.Bottom.LineWidth = 1.5;
ps.ParagraphFormat.HorizontalAlignment = docModule.HorizontalAlignment.Left;
}
// Body style: one font and one size for the body text
let normalStyle = doc.AddStyle({ builtinStyle: docModule.BuiltinStyle.Normal });
normalStyle.CharacterFormat.FontName = "Arial Unicode MS";
normalStyle.CharacterFormat.FontSize = 11;
// Heading 1 style
let heading1Style = doc.AddStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
heading1Style.CharacterFormat.FontName = "Arial Unicode MS";
heading1Style.CharacterFormat.FontSize = 14;
heading1Style.CharacterFormat.Bold = true;
heading1Style.CharacterFormat.TextColor = docModule.Color.FromArgb(42, 123, 136);
// Heading 2 style
let heading2Style = doc.AddStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
heading2Style.CharacterFormat.FontName = "Arial Unicode MS";
heading2Style.CharacterFormat.FontSize = 12;
heading2Style.CharacterFormat.Bold = true;
// Custom bulleted list style
let bulletList = doc.Styles.Add({ listType: docModule.ListType.Bulleted, name: "bulletList" });
doc.Styles.Add({ style: bulletList });
// Apply the styles: built-in styles by builtinStyle, custom styles by name
let paragraph = sec.AddParagraph();
paragraph.AppendText("Quarterly Operations Report");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Title });
paragraph = sec.AddParagraph();
paragraph.AppendText("Prepared by: Operations Management Department | Date: September 2026");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Normal });
paragraph = sec.AddParagraph();
paragraph.AppendText("Overall Progress");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
paragraph = sec.AddParagraph();
paragraph.AppendText("All three product lines stayed on plan this quarter, and the overall delivery pace was steady.");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Normal });
paragraph = sec.AddParagraph();
paragraph.AppendText("Key Items");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
paragraph = sec.AddParagraph();
paragraph.AppendText("Key Milestones");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
paragraph = sec.AddParagraph();
paragraph.AppendText("Core module integration testing completed");
paragraph.ListFormat.ApplyStyle("bulletList");
paragraph = sec.AddParagraph();
paragraph.AppendText("Trial run phase started");
paragraph.ListFormat.ApplyStyle("bulletList");
paragraph = sec.AddParagraph();
paragraph.AppendText("Pre-release review scheduled");
paragraph.ListFormat.ApplyStyle("bulletList");
paragraph = sec.AddParagraph();
paragraph.AppendText("Resource Input");
paragraph.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
paragraph = sec.AddParagraph();
paragraph.AppendText("Team capacity is tight at the moment; confirm the schedule early in the quarter.");
paragraph.ListFormat.ApplyStyle("bulletList");
// Define the output file name
const outputFileName = "Styles-result.docx";
// Save the document to the given path
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
doc.Dispose();
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>Create Styles and Apply Them to Paragraphs</h1>
<button onClick={Styles}>Generate</button>
</div>
);
}
export default App;
The built-in Title, Heading 1 and Heading 2 have been rewritten into one teal colour scheme, and the custom bulletList supplies the bullets

Copy Styles Between Documents
Companies often keep a "style master" document whose styles new documents have to follow. Rebuilding those styles one at a time by hand is slow and easy to miss something, so walk the Styles collection of the source document and add every style object to the target document instead.
document.Styles supports Count and get_Item(index), so the collection can be walked completely by index. Once the styles of the source document have been added to the target document, the paragraphs in the target that reference those style names immediately show the formatting of the source document.
This example uses two sample documents: CopyDocumentStyles1.docx is the source document with custom styles, and CopyDocumentStyles2.docx is the target document — some of its paragraphs reference style names that only the source document defines, but it does not define them itself, so before the copy those paragraphs are displayed with the default formatting.
function App() {
const CopyDocumentStyles = async () => {
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// Load the two sample files into the virtual file system (VFS)
let inputFileName_1 = "CopyDocumentStyles1.docx";
await window.spire.FetchFileToVFS(inputFileName_1, "", `${process.env.PUBLIC_URL}static/data/`);
let inputFileName_2 = "CopyDocumentStyles2.docx";
await window.spire.FetchFileToVFS(inputFileName_2, "", `${process.env.PUBLIC_URL}static/data/`);
// Load the source document (with the custom styles)
let srcDoc = new docModule.Document();
srcDoc.LoadFromFile(inputFileName_1);
// Load the target document (built-in styles only)
let destDoc = new docModule.Document();
destDoc.LoadFromFile(inputFileName_2);
// Take the style collection of the source document
let styles = srcDoc.Styles;
// Add them to the target document one by one
for (let i = 0; i < styles.Count; i++) {
let style = styles.get_Item(i);
destDoc.Styles.Add(style);
}
// Define the output file name
const outputFileName = "CopyDocumentStyles_result.docx";
// Save the document to the given path
destDoc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
destDoc.Dispose();
srcDoc.Dispose();
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>Copy the Styles of the Source Document into the Target Document</h1>
<button onClick={CopyDocumentStyles}>Generate</button>
</div>
);
}
export default App;
After the copy the target document has the custom styles of the source document, and the paragraphs that "referenced a style without carrying its formatting" are displayed correctly again

FAQ
The Normal style was changed, but not every body paragraph followed
Cause: Only styles that inherit from Normal are affected by it. If a paragraph carries direct formatting of its own (a per-paragraph CharacterFormat.FontName, for example), the direct formatting has a higher priority than the style and covers up what the style sets.
Solution: Control the appearance through styles consistently and remove the direct formatting from the paragraphs and the runs. Normal is commonly used to unify the body font and the font size:
let normalStyle = document.AddStyle({ builtinStyle: wasmModule.BuiltinStyle.Normal });
normalStyle.CharacterFormat.FontName = "Arial Unicode MS";
normalStyle.CharacterFormat.FontSize = 11;
The number of styles in the target document doubled after the copy
Cause: The walk copies every style of the source document across, and that includes a large number of built-in styles. Those style names usually already exist in the target document, and adding them one at a time creates duplicate entries.
Solution: This is the actual behaviour of the sample (the style collection grows noticeably). If a real project only needs the custom styles, filter by name first and copy only the styles the target document does not have yet:
for (let i = 0; i < srcDoc.Styles.Count; i++) {
let style = srcDoc.Styles.get_Item(i);
// Check whether the target document already has a style with the same name
let exists = false;
for (let j = 0; j < destDoc.Styles.Count; j++) {
if (destDoc.Styles.get_Item(j).Name === style.Name) {
exists = true;
break;
}
}
// Only add the styles that the target document is missing
if (!exists) {
destDoc.Styles.Add(style);
}
}
A custom style does not take effect when it is applied to a paragraph
Cause: ApplyStyle is called differently for built-in and custom styles — a built-in style takes a { builtinStyle } object, a custom style takes the style name as a string. Passing the wrong form is ignored silently.
Solution: Choose the form that matches where the style comes from:
// Built-in style
paragraph.ApplyStyle({ builtinStyle: wasmModule.BuiltinStyle.Heading1 });
// Custom style (the string name, which has to match the name used in Add)
paragraph.ListFormat.ApplyStyle("bulletList");
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.
