Building Docxion: An Open-Source Office Document Viewer for Android and the Web
Viewing a PDF inside an application is relatively straightforward.
Viewing Microsoft Office documents is a different story.
DOC, DOCX, XLS, XLSX, PPT, and PPTX all come with their own rendering challenges. If you want users to open these documents directly inside your application, you quickly end up choosing between complicated rendering stacks, external applications, proprietary SDKs, or solutions with licensing requirements that don't fit your project.
I wanted something simpler.
So I started building Docxion.
Docxion is an open-source document viewer focused on Microsoft Office formats, with an Android/Jetpack Compose integration and a reusable TypeScript/React viewer underneath.
And perhaps most importantly for me:
Docxion is Apache 2.0 licensed.
That means you can use it in open-source projects and commercial applications without having to purchase a separate commercial license for Docxion itself.
What is Docxion?
Docxion is currently structured around three main pieces:
- Docxion Android Library — a Kotlin/Jetpack Compose integration
- office-viewer — the underlying React/TypeScript viewer
- Example — an Android application demonstrating the integration
The Android library embeds the TypeScript viewer inside an Android WebView and exposes a native Kotlin API for interacting with it.
At a high level, the architecture looks like this:
Android Application
|
v
Docxion Android Library
|
v
Android WebView
|
v
TypeScript / JavaScript Viewer
|
v
Document Renderers
This separation is intentional.
The Android layer doesn't try to reimplement document rendering. Instead, it provides the native Android integration around the viewer.
That means the same underlying viewer can evolve independently from the Android API.
Why build another document viewer?
There are already document viewers and Office SDKs available.
The problem isn't simply that there aren't enough viewers.
The problem is integration.
When you're building an application, you don't necessarily want to:
- send documents to an external service;
- launch another application to view them;
- build an entire viewer yourself;
- couple your application to a proprietary SDK;
- or introduce licensing requirements that make an otherwise simple feature difficult to ship commercially.
Sometimes you just want:
My Application
|
+-- Open document
|
+-- Display document
|
+-- Search
|
+-- Select text
|
+-- Navigate
That's the problem space Docxion is trying to address.
The formats
Docxion is focused on Microsoft Office documents.
The current project targets:
| Format | Extension |
|---|---|
| Microsoft Word | .doc |
| Microsoft Word | .docx |
| Microsoft Excel | .xls |
| Microsoft Excel | .xlsx |
| Microsoft PowerPoint | .ppt |
| Microsoft PowerPoint | .pptx |
Actual support depends on the document renderers included underneath the viewer, so format support and rendering fidelity are still areas of ongoing development.
That's also one reason Docxion is currently labeled as early development.
The APIs, packaging, and project structure can change as the project evolves.
The interesting part: the Android bridge
One of the things I wanted to get right was the boundary between Kotlin and JavaScript.
An Android application shouldn't have to know that the viewer is implemented in TypeScript.
From the Android side, you interact with:
DocxionWebViewApi
The API mirrors the underlying JavaScript ViewerAPI.
For example:
api?.openFile(uri)
Once the viewer is ready, Android can perform operations such as:
- opening documents;
- closing documents;
- navigating pages;
- changing zoom;
- fitting the document to width or page;
- searching;
- navigating search results;
- reading selected text;
- changing themes;
- printing;
- destroying the viewer.
The Android library exposes the viewer through a Compose-friendly component:
DocxionViewer(
modifier = Modifier.fillMaxSize(),
callbacks = callbacks,
onApiCreated = { api ->
// Store the API for later operations
}
)
So from an application's perspective, the viewer behaves like a native component.
Kotlin to JavaScript
The communication path looks roughly like this:
Kotlin
|
v
DocxionWebViewApi
|
v
WebView.evaluateJavascript()
|
v
window.docxionApi
|
v
ViewerAPI
|
v
Document Viewer
The Android API intentionally stays close to the JavaScript API.
This makes the two sides easier to reason about and avoids creating two completely different abstractions for the same viewer.
JavaScript back to Android
The communication also works in the opposite direction.
The viewer can send events back to the Android application through a JavaScript bridge:
Document Viewer
|
v
AndroidCallbacks
|
v
window.DocxionAndroid
|
v
DocxionJsBridge
|
v
DocxionCallbacks
|
v
Android Application
The current callback surface includes events for:
- page changes;
- zoom changes;
- text selection;
- viewer readiness;
- errors;
- debug logging.
For example, an application can react when the user selects text inside a document without having to directly interact with the WebView's JavaScript environment.
The viewer API
The underlying TypeScript viewer exposes a relatively straightforward API.
A simplified view of it looks like:
interface ViewerAPI {
openFile(file: File | string): Promise<void>;
closeFile(): void;
goToPage(page: number): Promise<void>;
getCurrentPage(): number;
getTotalPages(): number;
setZoom(zoom: number): Promise<void>;
zoomIn(step?: number): Promise<void>;
zoomOut(step?: number): Promise<void>;
fitToWidth(): Promise<void>;
fitToPage(): Promise<void>;
search(query: string): Promise<SearchResult[]>;
clearSearch(): void;
goToNextMatch(): Promise<void>;
goToPreviousMatch(): Promise<void>;
getSelectedText(): string | null;
clearSelection(): void;
setTheme(theme: 'light' | 'dark'): void;
print(): void;
destroy(): void;
isReady(): boolean;
}
The Android DocxionWebViewApi provides the corresponding Kotlin-facing operations.
This API is deliberately about viewing, rather than editing documents.
Docxion isn't trying to become Microsoft Word or Excel.
The goal is to make document viewing an embeddable part of another application.
Search and text selection
A document viewer becomes much more useful once the document isn't just a bitmap on screen.
Docxion exposes search through the viewer API and can navigate between search matches.
It also exposes selected text:
getSelectedText(): string | null
This allows an application to react to text selection and potentially build functionality around it.
For example:
User selects text
|
v
Docxion viewer
|
v
Android callback
|
v
Your application
This is particularly useful for applications where the document is only one part of a larger workflow.
Why the WebView architecture?
A natural question is:
Why use a WebView on Android instead of implementing everything natively?
Because the viewer itself is a separate piece of software.
The rendering and viewer logic live in TypeScript/JavaScript. Android provides the native host and API around it.
This gives us a clean separation:
Docxion
|
+---------+---------+
| |
v v
TypeScript Viewer Android Library
| |
| |
Rendering/UI Native API
| |
+-------- WebView ---+
The advantage is that improvements to the viewer don't necessarily require redesigning the Android API.
It also means the viewer can exist independently from Android.
The office-viewer package exposes its own mountViewer() entry point:
mountViewer(
container,
options
);
So the project isn't fundamentally an Android-only viewer.
The Android library is an integration around the underlying web viewer.
Embedding it in an Android application
Docxion is distributed through JitPack.
The repository currently provides the dependency as:
implementation("com.github.mjrfusion:docxion:<version>")
After adding the JitPack repository, an Android project can embed the viewer using Jetpack Compose.
The basic structure is intentionally small:
DocxionViewer(
modifier = Modifier.fillMaxSize(),
onApiCreated = { api ->
viewerApi = api
}
)
Then a document can be opened through the API:
viewerApi?.openFile(uri)
The repository also contains an example Android application showing the integration, callbacks, navigation, zoom controls, and communication between Kotlin and the JavaScript viewer.
Apache 2.0
This is one of the most important parts of the project.
Docxion is released under the Apache License 2.0.
That makes it suitable for both open-source and commercial applications, subject to the terms of the Apache 2.0 license.
There is no separate Docxion commercial license that you need to purchase just because your application is commercial.
In other words:
Open source? Yes.
Commercial application? Yes.
GPL dependency? No.
Separate commercial license for Docxion? No.
That's a deliberate part of the project's direction.
I wanted developers to be able to evaluate Docxion based on whether it solves their technical problem, rather than first having to figure out whether its licensing model fits their business.
Of course, Docxion is made up of multiple components and document renderers, so users should always review the licenses of the specific dependencies distributed with the version they use. Apache 2.0 applies to the Docxion project itself.
This is still early
Docxion is not pretending to be a finished replacement for every Office viewer.
The repository is explicitly in early development.
That means:
- APIs may change;
- packaging may change;
- the viewer is still evolving;
- document compatibility will continue to improve;
- rendering edge cases are expected;
- the architecture itself may evolve.
I'd rather be explicit about that than pretend that Office document rendering is a solved problem.
There are a huge number of documents in the wild, and document rendering has plenty of unpleasant edge cases.
What I want Docxion to become
The long-term idea is straightforward:
Make document viewing something developers can embed instead of something they have to outsource.
I'd like Docxion to become useful for applications such as:
- document management systems;
- file managers;
- productivity applications;
- document vaults;
- enterprise applications;
- educational applications;
- offline document readers;
- any application that needs to display Office documents without handing the user off to another application.
The viewer should remain a reusable component.
The Android integration should remain a native-feeling API.
And the licensing should remain friendly to developers who want to build commercial software on top of it.
Try it
Docxion is available on GitHub:
The repository contains the Android library, the TypeScript/React viewer, and an example application.
If you're building an application that needs embedded Office document viewing, I'd be particularly interested in hearing about your use case.
I'd also love contributions around document compatibility, rendering quality, API design, testing, and additional integrations.
Office documents are a surprisingly deep rabbit hole.
This is my attempt at making that rabbit hole something developers can actually embed in their applications.
Top comments (0)