--- title: Excel Viewer in Visual Studio Code 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. [Visual Studio Code](https://code.visualstudio.com) is a popular code editor that supports extensions for customizing and enhancing functionality. This demo uses SheetJS in a VS Code extension to view Excel files directly within the editor. The extension leverages VS Code's `Custom Editor API`[^2] and `WebView API`[^1] to display XLSX data as HTML tables. The demo includes the full source code for the extension and installation instructions. :::note Tested Deployments This demo was verified in the following deployments: | Platform | OS Version | Architecture | Date | |:----------------|:------------------------|:------------------|:-----------| | VS Code 1.100.0 | macOS 15.3.1 | Darwin (arm64) | 2025-05-15 | ::: ## Integration Details The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be imported from any component or script in the extension. :::note > Install the package as a developer dependency. > Otherwise, `vsce`[^5] (Visual Studio Code Extension Manager) will **fail to package or publish** your extension correctly. {`\ npm rm --save xlsx npm i --save-dev https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} {`\ pnpm rm xlsx pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} {`\ yarn remove xlsx yarn add -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} ::: ## 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. ## Building the Extension ### Extension Entry Point The main entry point registers the custom editor provider: {`import * as vscode from 'vscode'; // highlight-start import { ExcelEditorProvider } from './excelEditorProvider'; // highlight-end export function activate(context: vscode.ExtensionContext) { // SheetJS Spreadsheet Viewer extension activating... // highlight-start const provider = ExcelEditorProvider.register(context); context.subscriptions.push(provider); // highlight-end } export function deactivate() {}`} 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. {`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 { // ... public static register(context: vscode.ExtensionContext): vscode.Disposable { return vscode.window.registerCustomEditorProvider( 'excelViewer.spreadsheet', new ExcelEditorProvider(context), { webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden ); } // ... }`} ### Reading Files The extension reads Excel files using the VS Code filesystem API and passes the data to SheetJS for parsing: {`export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider { // ... private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise { 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 { return new ExcelDocument(uri); } // This is called whenever the user opens a new editor async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise { const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel); const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); webviewPanel.webview.html = \`\${htmlTable}\`; } }`} ### 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 1. Create a new VS Code extension ```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 Enter - `What's the name of your extension?`: Type `sheetjs-demo` and press Enter - `What's the identifier of your extension?`: Press Enter - `What's the description of your extension?`: Press Enter - `Initialize a git repository?`: Type `n` and press Enter - `Which bundler to use?`: Select `webpack` and press Enter - `Which package manager to use?`: Select `pnpm` and press Enter ![Expected output](pathname:///vscode/yeo-code.png) - `Do you want to open the new folder with Visual Studio Code?`: Press Enter 2. [Install the dependencies](#integration-details) and start: {`\ pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz pnpm run watch `} 3. Create a new provider `excelEditorProivder.ts` and paste the following: {`import * as vscode from 'vscode'; import * as XLSX from 'xlsx'; class ExcelDocument implements vscode.CustomDocument { constructor(public readonly uri: vscode.Uri) { } dispose() { } } export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider { public static register(context: vscode.ExtensionContext): vscode.Disposable { return vscode.window.registerCustomEditorProvider( 'excelViewer.spreadsheet', new ExcelEditorProvider(context), { webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden ); } private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise { 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 { return new ExcelDocument(uri); } // This is called whenever the user opens a new editor async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise { const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel); const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); webviewPanel.webview.html = \`\${htmlTable}\`; } }`} 4. Register the custom editor provider with the main entry point `extension.ts` {`import * as vscode from 'vscode'; import { ExcelEditorProvider } from './excelEditorProvider'; export function activate(context: vscode.ExtensionContext) { // SheetJS Spreadsheet Viewer extension activating... const provider = ExcelEditorProvider.register(context); context.subscriptions.push(provider); } export function deactivate() {}`} 5. Registering the custom editor in your `package.json` file. {`\ "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" } ] }, `} 6. Inside the editor, open `src/extension.ts` and press F5 or run the command **Debug: Start Debugging** from the Command Pallet (⇧⌘P). This will compile and run the extension in a new Extension Development Host window. 7. Select the new VSCode Window and open a `.xlsx` or `.xls` file. ![Expected output](pathname:///vscode/extension-viewing-xls-file.png) --- ### Learn More You can check out [the complete SheetJS VS Code extension demo repository](https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension) - your feedback and contributions are welcome! [^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.