Please complete the following checklist (by adding [x]):
Context: The Proton community has been requesting ODT support across several UserVoice threads (1, 2, 3). A Proton team member noted in one thread that "there are no libraries whatsoever for ODT processing for browsers." This is no longer accurate.
odf-kit is a pure TypeScript library (Apache 2.0, ESM, zero dependencies beyond fflate) that generates, reads, and converts ODT files entirely client-side — no LibreOffice, no server required. It passes the OASIS ODF validator on every release.
As of v0.12.0 it includes lexicalToOdt() — a function that converts a Lexical SerializedEditorState directly to a valid .odt file. It handles the node types registered in AllNodes.ts: paragraphs, headings, blockquotes, code blocks, lists (including CustomListNode), tables, links, images, horizontal rules, and inline formatting.
The integration point in this codebase is well-defined:
New file: applications/docs-editor/src/app/Conversion/Exporter/EditorOdtExporter.ts
typescriptimport { lexicalToOdt } from 'odf-kit/lexical'
import { EditorExporter } from './EditorExporter'
export class EditorOdtExporter extends EditorExporter {
async export(): Promise<Uint8Array> {
return lexicalToOdt(this.editor.getEditorState().toJSON(), {
pageFormat: 'A4',
fetchImage: async (src) => {
const b64 = await this.callbacks.fetchExternalImageAsBase64(src)
if (!b64) return undefined
const binary = atob(b64.split(',')[1] ?? b64)
return Uint8Array.from(binary, c => c.charCodeAt(0))
},
})
}
}
Edit: ExportDataFromEditorState.ts — add one case:
typescriptcase 'odt':
return new EditorOdtExporter(editorState, callbacks).export()
Edit: DataTypesThatDocumentCanBeExportedAs in @proton/docs-shared — add 'odt' to the union type.
Posting here in case it's useful. Happy to answer any questions about the library.
Please complete the following checklist (by adding [x]):
Context: The Proton community has been requesting ODT support across several UserVoice threads (1, 2, 3). A Proton team member noted in one thread that "there are no libraries whatsoever for ODT processing for browsers." This is no longer accurate.
odf-kit is a pure TypeScript library (Apache 2.0, ESM, zero dependencies beyond fflate) that generates, reads, and converts ODT files entirely client-side — no LibreOffice, no server required. It passes the OASIS ODF validator on every release.
As of v0.12.0 it includes lexicalToOdt() — a function that converts a Lexical SerializedEditorState directly to a valid .odt file. It handles the node types registered in AllNodes.ts: paragraphs, headings, blockquotes, code blocks, lists (including CustomListNode), tables, links, images, horizontal rules, and inline formatting.
The integration point in this codebase is well-defined:
New file: applications/docs-editor/src/app/Conversion/Exporter/EditorOdtExporter.ts
typescriptimport { lexicalToOdt } from 'odf-kit/lexical'
import { EditorExporter } from './EditorExporter'
export class EditorOdtExporter extends EditorExporter {
async export(): Promise<Uint8Array> {
return lexicalToOdt(this.editor.getEditorState().toJSON(), {
pageFormat: 'A4',
fetchImage: async (src) => {
const b64 = await this.callbacks.fetchExternalImageAsBase64(src)
if (!b64) return undefined
const binary = atob(b64.split(',')[1] ?? b64)
return Uint8Array.from(binary, c => c.charCodeAt(0))
},
})
}
}
Edit: ExportDataFromEditorState.ts — add one case:
typescriptcase 'odt':
return new EditorOdtExporter(editorState, callbacks).export()
Edit: DataTypesThatDocumentCanBeExportedAs in @proton/docs-shared — add 'odt' to the union type.
Posting here in case it's useful. Happy to answer any questions about the library.