Turn HTML headings, paragraphs, links and tables into editable Word content, not a screenshot of a web page.
dotnet add package RecursiveAI.OneDocument.DocumentsRequires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.
using RecursiveAI.OneDocument.Documents; using var doc = Document.FromHtml( "<h1>Report</h1><p>Hello.</p>"); doc.SaveAs("report.docx");
Writes report.docx containing the “Report” heading and “Hello.” paragraph. The snippet prints no console output.
Unzip the example, then dotnet run.
Full program
The full program embeds all its HTML: a “Quarterly report” heading, a paragraph linking to https://example.com/report, a two-column table with North/1200, and a script that is not imported. No input download or network request is needed.
using RecursiveAI.OneDocument.Documents; const string html = """ <h1>Quarterly report</h1> <p>Read the <a href="https://example.com/report">report</a>.</p> <table><tr><th>Region</th><th>Revenue</th></tr> <tr><td>North</td><td>1200</td></tr></table> <script>alert('not imported');</script> """; using var doc = Document.FromHtml(html); foreach (var loss in doc.ImportLoss!.Items) Console.WriteLine($"{loss.Code}: {loss.Count}"); doc.SaveAs("report.docx"); using var reopened = Document.Open("report.docx"); foreach (var paragraph in reopened.Paragraphs) Console.WriteLine(paragraph.Text); Console.WriteLine($"Tables: {reopened.Tables.Count()}"); Console.WriteLine($"Links: {reopened.Paragraphs.SelectMany(p => p.Inlines().OfType<Hyperlink>()).Count()}");
loss.html-script: 1 Quarterly report Read the report. Region Revenue North 1200 Tables: 1 Links: 1
The import loss report lists the dropped script. Input beyond the configured XML-depth or part-size bounds can throw OfficeLimitException.
Variations
Read an HTML file instead of a string. This creates its own small HTML input file.
using RecursiveAI.OneDocument.Documents; File.WriteAllText("page.html", "<p>Saved HTML input.</p>"); using var doc = Document.Open("page.html"); doc.SaveAs("from-file.docx"); Console.WriteLine(doc.Paragraphs.First().Text);
Saved HTML input.Related recipes
The short answer
Call Document.FromHtml(html) and save the result with a .docx extension. Read ImportLoss.Items before saving to see reported content that did not carry over. For a file on disk, Document.Open("page.html") recognizes HTML by its content.
How to convert HTML to DOCX?
Use the string entry point for HTML you already hold in memory, or the file entry point shown in the variation. Saving as DOCX serializes the imported word-processing document. The HTML documentation lists the mapping from elements and computed styles to Word structures.
Headings become heading styles. Paragraph-like blocks with inline content become paragraphs. Links become hyperlink relationships or internal anchors. Tables retain rows and cells, including documented mappings for merged cells, repeated header rows, borders, shading and widths. These are document structures you can edit after import; they are not retained as a live HTML page.
The example prints table-cell text because paragraph enumeration includes paragraphs inside tables. It then separately counts top-level tables and paragraph hyperlinks. Seeing those cell values in the text output does not mean the table was flattened: the saved document still has a table.
How can I convert HTML code to a Word document?
Keep the HTML self-contained when you want predictable inputs. Inline style attributes and style elements participate in the computed styles read by the importer. The documented subset includes bold, italic, underline, font family and size, text and background colors, paragraph alignment, indents, spacing, borders and shading. Lists become numbering definitions, and preformatted content preserves spaces and line breaks.
Do not treat that subset as a browser layout guarantee. This path maps content and selected computed properties into DOCX. It does not execute JavaScript to generate missing page content. Forms, embedded frames, media, inline SVG and MathML have documented loss codes rather than an interactive Word equivalent. Check the report against what your application needs before accepting the output.
The report groups repeated losses by code and accumulates their counts. An empty report is useful information about reported conversion losses, but should not be used as a visual comparison of the HTML and Word layouts. Open representative output in your target document application when page appearance matters.
Can I convert HTML to DOCX for free in C#?
The downloadable project uses the published RecursiveAI.OneDocument.Documents package under MIT OR Apache-2.0. It runs locally with .NET 10 and does not need a service account or conversion API key. The example includes the source and its package version so you can change the input without using a hosted converter.
External resources need an explicit policy. Import does not fetch linked style sheets or open image URLs on its own. A linked style sheet is reported as dropped. Images embedded as supported data: URIs can become inline pictures; an external image must be supplied through HtmlImportOptions.ImageResolver or is reported, with its alt text retained.
That resolver receives the source string and returns bytes. If you add one, your code decides which resources may be read; the import operation itself does not become a web crawler. The self-contained fixture avoids that extra dependency entirely. For an actual web page, supply the HTML and resources you intend to convert rather than expecting browser navigation, script execution or remote asset loading.