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
description: View Excel files directly in VS Code. Seamlessly browse spreadsheet data without leaving your editor using SheetJS. Navigate between worksheets and pages of data with a responsive
pagination_prev: demos/cloud/index
pagination_next: demos/bigdata/index
sidebar_custom_props:
summary: View Excel files directly within Visual Studio Code
---
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
Code "Custom Editor API"[^2] and "WebView API"[^1] to display spreadsheet data
as HTML tables.
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
:::tip pass
["SheetJS Spreadsheet Viewer" ](https://marketplace.visualstudio.com/items?itemName=asadbek.sheetjs-demo )
is a sample extension based on this demo.
[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
This demo was verified in the following deployments:
2025-05-18 20:09:19 +00:00
| Platform | Architecture | Date |
|:-----------------|:-------------|:-----------|
| VS Code 1.100.0 | `darwin-arm` | 2025-05-15 | TODO
| VSCodium 1.100.0 | `darwin-arm` | 2025-05-15 | TODO
| Cursor | `win11-arm` | 2025-05-15 | TODO
| Windsurf | `win11-arm` | 2025-05-15 | TODO
| Void | `win11-arm` | 2025-05-15 | TODO
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
imported from any component or 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
2025-05-18 20:09:19 +00:00
The module must be installed as a development dependency. If the module is
installed as a normal dependency, `vsce` [^5] (Visual Studio Code Extension
Manager) will fail to package or publish your extension correctly.
2025-05-15 05:41:40 +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`}
2025-05-15 05:41:40 +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`}
2025-05-15 05:41:40 +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`}
2025-05-15 05:41:40 +00:00
< / CodeBlock >
< / TabItem >
< / Tabs >
:::
## Extension Architecture
The VS Code Spreadsheet viewer extension has three main components:
- **Extension Entry Point:** Registers the extension with VS Code
- **Custom Editor Provider:** Handles Excel files and converts them to web content
- **WebView Content:** Displays Excel data as HTML tables
The extension uses VS Code's `Custom Editor API` [^2] to register as a handler for Excel files. When a file is opened,
SheetJS parses it and displays the data in a WebView component.
### Extension Entry Point
The main entry point registers the custom editor provider:
2025-05-18 20:09:19 +00:00
```ts title="src/extension.ts"
import * as vscode from 'vscode';
// highlight-start
import { ExcelEditorProvider } from './excelEditorProvider';
// highlight-end
export function activate(context: vscode.ExtensionContext) {
// SheetJS Spreadsheet Viewer extension activating...
2025-05-15 05:41:40 +00:00
// highlight-start
2025-05-18 20:09:19 +00:00
const provider = ExcelEditorProvider.register(context);
context.subscriptions.push(provider);
2025-05-15 05:41:40 +00:00
// highlight-end
2025-05-18 20:09:19 +00:00
}
export function deactivate() {}`}
```
2025-05-15 05:41:40 +00:00
The `custom editor` [^3] is configured to support specific file types, giving us complete control over how each file is
presented to the user. Additionally, `custom document` [^4] enables us to maintain and persist the state of each individual
file that's opened.
< CodeBlock language = "typescript" value = "typescript" title = "src/excelEditorProvider.ts" >
{`import * as vscode from 'vscode';
// highlight-start
import * as XLSX from 'xlsx';
import { ExcelDocument } from './excelDocument';
// highlight-end
// A simple class to store document state (one per opened file)
class ExcelDocument implements vscode.CustomDocument {
constructor(public readonly uri: vscode.Uri) {}
dispose() {}
}
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
// ...
public static register(context: vscode.ExtensionContext): vscode.Disposable {
return vscode.window.registerCustomEditorProvider(
'excelViewer.spreadsheet',
2025-05-18 20:09:19 +00:00
new ExcelEditorProvider(),
2025-05-15 05:41:40 +00:00
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
);
}
// ...
}`}
< / CodeBlock >
### Reading Files
2025-05-18 20:09:19 +00:00
2025-05-15 05:41:40 +00:00
The extension reads Excel files using the VS Code filesystem API and passes
the data to SheetJS for parsing:
< CodeBlock language = "typescript" value = "typescript" title = "src/excelEditorProvider.ts" >
{`export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
// ...
private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< XLSX.WorkBook > {
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
const options: XLSX.ParsingOptions = {
type: 'array',
cellStyles: true,
cellDates: true,
};
return XLSX.read(new Uint8Array(data), options); // returns a XLSX.WorkBook
}
// 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);
}
// This is called whenever the user opens a new editor
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< void > {
const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel);
const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
webviewPanel.webview.html = \`<!DOCTYPE html> < html >< body > \${htmlTable}</ body ></ html > \`;
}
}`}
< / CodeBlock >
### 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
2025-05-18 20:09:19 +00:00
1) 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 >
- `What's the identifier of your extension?` : Press < kbd > Enter</ kbd >
- `What's the description of your extension?` : Press < kbd > Enter</ kbd >
- `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 >

- `Do you want to open the new folder with Visual Studio Code?` : Press < kbd > Enter</ kbd >
2025-05-18 20:09:19 +00:00
2) [Install the dependencies ](#integration-details ) 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 >
2025-05-18 20:09:19 +00:00
3) Save the following code snippet to `src/excelEditorProvider.ts` :
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
< CodeBlock language = "typescript" value = "typescript" title = "src/excelEditorProvider.ts" > {`\
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
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< ExcelDocument > {
2025-05-18 20:09:19 +00:00
public static register(context: vscode.ExtensionContext): vscode.Disposable {
return vscode.window.registerCustomEditorProvider(
'excelViewer.spreadsheet',
new ExcelEditorProvider(),
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
);
}
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< XLSX.WorkBook > {
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
const options: XLSX.ParsingOptions = {
type: 'array',
cellStyles: true,
cellDates: true,
};
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
return XLSX.read(new Uint8Array(data), options); // returns a XLSX.WorkBook
}
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
// 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-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
// This is called whenever the user opens a new editor
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise< void > {
const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel);
const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
webviewPanel.webview.html = \`<!DOCTYPE html> < html >< body > \${htmlTable}</ body ></ html > \`;
}
}`}
2025-05-15 05:41:40 +00:00
< / CodeBlock >
2025-05-18 20:09:19 +00:00
4) Register the custom editor provider in `src/extension.ts` :
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
< CodeBlock language = "typescript" value = "typescript" title = "src/extension.ts (replace contents)" > {`\
import * as vscode from 'vscode';
import { ExcelEditorProvider } from './excelEditorProvider';
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
export function activate(context: vscode.ExtensionContext) {
// SheetJS Spreadsheet Viewer extension activating...
const provider = ExcelEditorProvider.register(context);
context.subscriptions.push(provider);
}
export function deactivate() {}`}
2025-05-15 05:41:40 +00:00
< / CodeBlock >
2025-05-18 20:09:19 +00:00
5) Register the custom editor in the `contributes` section of `package.json` :
2025-05-15 05:41:40 +00:00
2025-05-18 20:09:19 +00:00
< CodeBlock language = "json" value = "json" title = "package.json (add highlighted lines)" > {`\
2025-05-15 05:41:40 +00:00
"main": "./dist/extension.js",
"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"
}
]
},
`}
< / CodeBlock >
6. Inside the editor, open `src/extension.ts` and press < kbd > F5</ kbd > or run the command **Debug: Start Debugging**
2025-05-18 20:09:19 +00:00
from the Command Palette (< kbd > ⇧⌘P< / kbd > ). This will compile and run the extension in a new Extension Development Host window.
2025-05-15 05:41:40 +00:00
7. Select the new VSCode Window and open a `.xlsx` or `.xls` file.
---
[^1]: See [`Webview API` ](https://code.visualstudio.com/api/extension-guides/webview ) for more details.
[^2]: See [`Custom Editor API` ](https://code.visualstudio.com/api/extension-guides/custom-editors ) documentation for more details.
[^3]: See [`Custom Editor` ](https://code.visualstudio.com/api/extension-guides/custom-editors#custom-editor ) for more details.
[^4]: See [`CustomDocument` ](https://code.visualstudio.com/api/extension-guides/custom-editors#customdocument ) for more details.
[^5]: See [`Visual Studio Code Extension Manager` ](https://code.visualstudio.com/api/working-with-extensions/publishing-extension ) for more details.