2025-05-15 05:41:40 +00:00
---
2025-05-18 20:09:19 +00:00
title: Visualizing Data in VS Code
2025-05-15 05:41:40 +00:00
sidebar_label: Visual Studio Code
2026-03-06 04:51:03 +00:00
description: View Excel files directly in VS Code. Seamlessly browse spreadsheet data using SheetJS. Navigate between worksheets and pages of data with a responsive interface.
2025-05-15 05:41:40 +00:00
pagination_prev: demos/cloud/index
pagination_next: demos/bigdata/index
sidebar_custom_props:
2026-03-06 04:51:03 +00:00
summary: View Excel spreadsheets directly within Visual Studio Code
2025-05-15 05:41:40 +00:00
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
[SheetJS ](https://sheetjs.com ) is a JavaScript library for reading and writing
data from spreadsheets.
2025-05-18 20:09:19 +00:00
[Visual Studio Code ](https://code.visualstudio.com ) is a popular code editor
that supports JavaScript extensions for customizing and enhancing functionality.
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
The ["Complete Example" ](#complete-example ) uses SheetJS in a VS Code extension
to view Excel files directly within the editor. The extension leverages the VS
2026-03-06 04:51:03 +00:00
Code "WebView API"[^1] and "Custom Editor API"[^2] to display spreadsheet data
2025-05-18 20:09:19 +00:00
as HTML tables.
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
:::tip pass
2026-03-06 04:51:03 +00:00
"SheetJS Spreadsheet Viewer" is a sample extension based on this demo. It is
available on [Open VSX ](https://open-vsx.org/extension/asadbek/sheetjs-demo ) and
[VSCode Marketplace ](https://marketplace.visualstudio.com/items?itemName=asadbek.sheetjs-demo )
2025-05-18 20:09:19 +00:00
[The source code ](https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension )
is available on the SheetJS Git server. Feedback and contributions are welcome!
:::

2025-05-15 05:41:40 +00:00
:::note Tested Deployments
2026-03-06 19:04:23 +00:00
This demo was tested in the following deployments:
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
| Platform | Architecture | Date |
|:--------------------------------------------------|:-------------|:-----------|
| [VSCodium 1.109.51242 ](https://vscodium.com/ ) | `darwin-arm` | 2026-03-05 |
| [VS Code 1.110.0 ](https://code.visualstudio.com/ ) | `win11-arm` | 2026-03-05 |
| [Antigravity 1.19.6 ](https://antigravity.google/ ) | `linux-arm` | 2026-03-05 |
:::
:::danger Telemetry and Data Exfiltration
VSCode and many forks embed telemetry and send code to third-party servers.
For example, Antigravity includes AI features that are powered by Google Gemini
and other cloud AI services. These features necessitate code exfiltration.
**[VSCodium](https://vscodium.com/) does not include AI features or telemetry!**
2025-05-15 05:41:40 +00:00
:::
## Integration Details
2025-05-18 20:09:19 +00:00
The [SheetJS NodeJS Module ](/docs/getting-started/installation/nodejs ) can be
2026-03-06 19:04:23 +00:00
imported from any script in the extension.
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
:::caution pass
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
The SheetJS NodeJS module must be installed as a development dependency. If the
module is installed as a normal dependency, the `vsce` [^3] command-line tool
will fail to package or publish the exxtension.
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
< Tabs groupId = "pm" >
< TabItem value = "npm" label = "npm" >
< CodeBlock language = "bash" > {`\
2025-05-18 20:09:19 +00:00
npm rm --save xlsx
npm i --save-dev https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2026-03-06 04:51:03 +00:00
< / CodeBlock >
< / TabItem >
< TabItem value = "pnpm" label = "pnpm" >
< CodeBlock language = "bash" > {`\
2025-05-18 20:09:19 +00:00
pnpm rm xlsx
pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2026-03-06 04:51:03 +00:00
< / CodeBlock >
< / TabItem >
< TabItem value = "yarn" label = "Yarn" default >
< CodeBlock language = "bash" > {`\
2025-05-18 20:09:19 +00:00
yarn remove xlsx
yarn add -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2026-03-06 04:51:03 +00:00
< / CodeBlock >
2025-05-15 05:41:40 +00:00
< / TabItem >
2026-03-06 04:51:03 +00:00
< / Tabs >
2025-05-15 05:41:40 +00:00
:::
2026-03-06 19:04:23 +00:00
The core extension APIs are available in the `vscode` package. A TypeScript
extension typically uses "glob imports" to load SheetJS and VSCode features:
```ts title="Importing SheetJS and VSCode features"
import * as vscode from 'vscode';
import * as XLSX from 'xlsx';
```
2025-05-15 05:41:40 +00:00
## Extension Architecture
2026-03-06 19:04:23 +00:00
VSCode Extensions for processing custom file types use the Custom Editor API[^2]
for lifecycle events. This involves a number of moving parts:
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
1) "Custom Document" for managing file metadata
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
2) "Custom Editor Provider" for processing file data and generating previews
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
3) Registration during extension lifecycle events.
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
4) Advertisement of filetype support in extension metadata.
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
When a spreadsheet is opened, the extension will use SheetJS methods to parse
the raw file and display the data in a HTML table.
2025-05-18 20:09:19 +00:00
2026-03-06 19:04:23 +00:00
### Custom Documents
Extensions must provide a class that implements `vscode.CustomDocument` [^4].
```ts title="Simple CustomDocument"
class ExcelDocument implements vscode.CustomDocument {
constructor(public readonly uri: vscode.Uri) { }
dispose() { }
2025-05-18 20:09:19 +00:00
}
```
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
### Editor Provider
Extensions that read data should implement `vscode.CustomReadonlyEditorProvider`
with a generic parameter for the custom document type.
The `openCustomDocument` method takes a `vscode.Uri` and is expected to return a
new document:
```ts title="src/extension.ts (snippet)"
class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
async openCustomDocument(uri: vscode.Uri): Promise< ExcelDocument > {
return new ExcelDocument(uri);
2025-05-15 05:41:40 +00:00
}
2026-03-06 19:04:23 +00:00
}
```
### Reading Files
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
The `FileSystemProvider` API[^5], available at `vscode.workspace.fs` , exposes
common filesystem operations including reading raw data from files and watching
for changes.
The `resolveCustomEditor` [^6] method of the `CustomEditorProvider` will be
called when a file is opened. The first argument is a `CustomDocument` whose
`uri` property points to the location of the file.
`vscode.workspace.fs.readFile` [^5] returns a promise that resolves to a
`Uint8Array` containing the raw binary data. This `Uint8Array` can be passed to
the SheetJS [`read` ](/docs/api/parse-options ) method:
```ts title="src/extension.ts (snippet)"
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
// ...
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< void > {
// read the raw bytes from the file
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
// parse the file data
const wb: XLSX.WorkBook = XLSX.read(data);
// At this point, `wb` is a SheetJS Workbook Object
2025-05-15 05:41:40 +00:00
// ...
2026-03-06 19:04:23 +00:00
}
// ...
}
```
### Previewing Data
The `resolveCustomEditor` [^6] method of the `CustomEditorProvider` will be
called when a file is opened. The second argument is a `WebviewPanel` [^7].
The `webview.html` nested property of the `WebviewPanel` controls the displayed
HTML. Extensions can use SheetJS [API methods ](/docs/api/ ).
The SheetJS [`sheet_to_html` ](/docs/api/utilities/html#html-table-output ) method
generates a simple HTML table. The following snippet displays the data of the
first worksheet:
```ts title="src/extension.ts (snippet)"
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
// ...
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< void > {
2025-05-15 05:41:40 +00:00
// ...
2026-03-06 19:04:23 +00:00
// continuing from "Reading Files", `wb` is a SheetJS Workbook Object
const first_sheet = wb.Sheets[wb.SheetNames[0]];
webviewPanel.webview.html = XLSX.utils.sheet_to_html(first_sheet);
}
// ...
}
```
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
### Registration
The exported `activate` method registers the editor provider. The first argument
to `registerCustomEditorProvider` is expected to be a unique name that will be
referenced later.
```ts title="src/extension.ts (snippet)"
export function activate(context: vscode.ExtensionContext) {
const provider = vscode.window.registerCustomEditorProvider(
'excelViewer.spreadsheet',
new ExcelEditorProvider(),
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
);
context.subscriptions.push(provider);
}
```
### Filetype Support
2025-05-18 20:09:19 +00:00
2026-03-06 19:04:23 +00:00
Extensions must announce custom editor file type support in `package.json` .
The `selector` property[^8] is expected to include "Glob Pattterns"[^9].
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
The demo uses the following `package.json` snippet to announce support for `xls`
and `xlsx` spreadsheets:
```json title="package.json (snippet)"
"contributes": {
"customEditors": [
{
// ... other properties including displayName
// highlight-start
// The viewType must match the first argument of `registerCustomEditorProvider`
"viewType": "excelViewer.spreadsheet",
"selector": [
{ "filenamePattern": "*.xlsx" },
{ "filenamePattern": "*.xls" }
]
// highlight-end
}
],
2025-05-15 05:41:40 +00:00
// ...
2026-03-06 19:04:23 +00:00
},
```
2025-05-15 05:41:40 +00:00
### Usage Flow
```mermaid
sequenceDiagram
actor User
participant VSCode as VS Code
participant Provider as ExcelEditorProvider
participant SheetJS
participant WebView
User->>VSCode: Open .xlsx file
VSCode->>Provider: openCustomDocument(uri)
Provider-->>VSCode: return ExcelDocument
VSCode->>Provider: resolveCustomEditor(document, webviewPanel)
Provider->>VSCode: workspace.fs.readFile(document.uri)
VSCode-->>Provider: return file data
Provider->>SheetJS: XLSX.read(data, options)
SheetJS-->>Provider: return workbook
Provider->>SheetJS: XLSX.utils.sheet_to_html(sheet)
SheetJS-->>Provider: return HTML
Provider->>WebView: set webview.html
WebView-->>User: Display Excel data
```
## Complete Example
2026-03-06 04:51:03 +00:00
:::caution pass
To avoid conflicts with existing extensions, it is strongly recommended to test
with a different VSCode fork. For example, VSCode and Antigravity users should
install and use VSCodium for extension development.
:::
1) Download the [`pres.xlsx` ](https://docs.sheetjs.com/pres.xlsx ) sample file.
2) Create a new VS Code extension
2025-05-15 05:41:40 +00:00
```bash
npx --package yo --package generator-code -- yo code
```
When prompted, enter the following options:
- `What type of extension do you want to create?` : Select `New Extension (TypeScript)` and press < kbd > Enter</ kbd >
- `What's the name of your extension?` : Type `sheetjs-demo` and press < kbd > Enter</ kbd >
2026-03-06 04:51:03 +00:00
- `What's the identifier of your extension?` : Press < kbd > Enter</ kbd > (use the default `sheetjs-demo` )
- `What's the description of your extension?` : Press < kbd > Enter</ kbd > (leave blank)
2025-05-15 05:41:40 +00:00
- `Initialize a git repository?` : Type `n` and press < kbd > Enter</ kbd >
- `Which bundler to use?` : Select `webpack` and press < kbd > Enter</ kbd >
- `Which package manager to use?` : Select `pnpm` and press < kbd > Enter</ kbd >

2026-03-06 04:51:03 +00:00
3) Install the SheetJS library and start the dev server:
2025-05-15 05:41:40 +00:00
< CodeBlock language = "bash" > {`\
2025-05-18 20:09:19 +00:00
cd sheetjs-demo
2025-05-15 05:41:40 +00:00
pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
pnpm run watch
`}
< / CodeBlock >
2026-03-06 19:04:23 +00:00
4) Launch a new window with the VSCode fork and open the `sheetjs-demo` folder.
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
5) Save the following codeblock to `src/extension.ts` :
2026-03-06 04:51:03 +00:00
```ts title="src/extension.ts (replace contents)"
2025-05-18 20:09:19 +00:00
import * as vscode from 'vscode';
import * as XLSX from 'xlsx';
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
class ExcelDocument implements vscode.CustomDocument {
constructor(public readonly uri: vscode.Uri) { }
dispose() { }
}
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
// This is called when the first time an editor for a given resource is opened
async openCustomDocument(uri: vscode.Uri): Promise< ExcelDocument > {
return new ExcelDocument(uri);
2025-05-18 20:09:19 +00:00
}
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
// This is called whenever the user opens a new editor
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< void > {
2025-05-18 20:09:19 +00:00
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
const options: XLSX.ParsingOptions = { cellStyles: true, cellDates: true };
const wb: XLSX.WorkBook = XLSX.read(data, options);
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
const first_sheet = wb.Sheets[wb.SheetNames[0]];
webviewPanel.webview.html = XLSX.utils.sheet_to_html(first_sheet);
2025-05-18 20:09:19 +00:00
}
2026-03-06 04:51:03 +00:00
}
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
export function activate(context: vscode.ExtensionContext) {
2026-03-06 04:51:03 +00:00
const provider = vscode.window.registerCustomEditorProvider(
'excelViewer.spreadsheet',
new ExcelEditorProvider(),
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
);
2025-05-18 20:09:19 +00:00
context.subscriptions.push(provider);
}
2026-03-06 04:51:03 +00:00
export function deactivate() {}
```
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
6) Add the highlighted lines to the `contributes` section of `package.json` :
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
```json title="package.json (add highlighted lines)"
2025-05-15 05:41:40 +00:00
"contributes": {
// highlight-start
"customEditors": [
{
"viewType": "excelViewer.spreadsheet",
"displayName": "SheetJS Demo",
"selector": [
{ "filenamePattern": "*.xlsx" },
{ "filenamePattern": "*.xls" }
]
}
],
// highlight-end
"commands": [
{
"command": "sheetjs-demo.helloWorld",
"title": "Hello World"
}
]
},
2026-03-06 04:51:03 +00:00
```
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
7) In the editor, open the Command Palette (Help > "Show All Commands" from the
2026-03-06 04:51:03 +00:00
menu), type `Debug: Start` and select `Debug: Start Debugging` .
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
This will compile and run the extension in a new Extension Development Host window.
2025-05-15 05:41:40 +00:00
2026-03-06 19:04:23 +00:00
8) Drag and drop the `pres.xlsx` test file into the new window. If drag and drop
2026-03-06 04:51:03 +00:00
is not available, click "Open..." in the Welcome screen and select the file.
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
A new `pres.xlsx` tab will show the contents of the file.
:::info pass
When this demo was last tested, the default project assumed VSCode version
1.109.0 or later. Antigravity 1.19.6 is aligned to VSCode 1.107.0. The default
extension will not run in Antigravity.
This can be fixed by changing the `vscode` field in `package.json` . When this
demo was last tested, it was safe to set a minimum version of `^1.100.0` :
```json title="package.json (change highlighted line)"
"engines": {
// highlight-next-line
"vscode": "^1.100.0"
}
```
:::
2025-05-15 05:41:40 +00:00
2026-03-06 04:51:03 +00:00
[^1]: See [`Webview API` ](https://code.visualstudio.com/api/extension-guides/webview ) in the VSCode documentation for more details.
[^2]: See [`Custom Editor API` ](https://code.visualstudio.com/api/extension-guides/custom-editors ) in the VSCode documentation for more details.
[^3]: See [`vsce` ](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#vsce ) in the VSCode documentation for more details.
2026-03-06 19:04:23 +00:00
[^4]: See [`CustomDocument` ](https://code.visualstudio.com/api/references/vscode-api#CustomDocument ) in the VSCode API documentation for more details.
[^5]: See [`FileSystemProvider` ](https://code.visualstudio.com/api/references/vscode-api#FileSystemProvider ) in the VSCode API documentation for more details.
[^6]: See [`CustomEditorProvider<T>` ](https://code.visualstudio.com/api/references/vscode-api#CustomEditorProvider<T> ) in the VSCode API documentation for more details.
[^7]: See [`WebviewPanel` ](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel ) in the VSCode API documentation for more details.
[^8]: See [`contributes.customEditors` ](https://code.visualstudio.com/api/references/contribution-points#contributes.customEditors ) in the VSCode API documentation for more details.
[^9]: See ["Glob Patterns Reference" ](https://code.visualstudio.com/docs/editor/glob-patterns ) in the VSCode documentation for more details.