docs.sheetjs.com/docz/docs/03-demos/32-extensions/05-vscode.md
2026-03-06 14:04:23 -05:00

15 KiB

title sidebar_label description pagination_prev pagination_next sidebar_custom_props
Visualizing Data in VS Code Visual Studio Code View Excel files directly in VS Code. Seamlessly browse spreadsheet data using SheetJS. Navigate between worksheets and pages of data with a responsive interface. demos/cloud/index demos/bigdata/index
summary
View Excel spreadsheets 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 is a JavaScript library for reading and writing data from spreadsheets.

Visual Studio Code is a popular code editor that supports JavaScript extensions for customizing and enhancing functionality.

The "Complete Example" uses SheetJS in a VS Code extension to view Excel files directly within the editor. The extension leverages the VS Code "WebView API"1 and "Custom Editor API"2 to display spreadsheet data as HTML tables.

:::tip pass

"SheetJS Spreadsheet Viewer" is a sample extension based on this demo. It is available on Open VSX and VSCode Marketplace

The source code is available on the SheetJS Git server. Feedback and contributions are welcome!

:::

Expected output

:::note Tested Deployments

This demo was tested in the following deployments:

Platform Architecture Date
VSCodium 1.109.51242 darwin-arm 2026-03-05
VS Code 1.110.0 win11-arm 2026-03-05
Antigravity 1.19.6 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 does not include AI features or telemetry!

:::

Integration Details

The SheetJS NodeJS Module can be imported from any script in the extension.

:::caution pass

The SheetJS NodeJS module must be installed as a development dependency. If the module is installed as a normal dependency, the vsce3 command-line tool will fail to package or publish the exxtension.

{\ 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}

:::

The core extension APIs are available in the vscode package. A TypeScript extension typically uses "glob imports" to load SheetJS and VSCode features:

import * as vscode from 'vscode';
import * as XLSX from 'xlsx';

Extension Architecture

VSCode Extensions for processing custom file types use the Custom Editor API2 for lifecycle events. This involves a number of moving parts:

  1. "Custom Document" for managing file metadata

  2. "Custom Editor Provider" for processing file data and generating previews

  3. Registration during extension lifecycle events.

  4. Advertisement of filetype support in extension metadata.

When a spreadsheet is opened, the extension will use SheetJS methods to parse the raw file and display the data in a HTML table.

Custom Documents

Extensions must provide a class that implements vscode.CustomDocument4.

class ExcelDocument implements vscode.CustomDocument {
  constructor(public readonly uri: vscode.Uri) { }
  dispose() { }
}

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:

class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
  async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> {
    return new ExcelDocument(uri);
  }
}

Reading Files

The FileSystemProvider API5, available at vscode.workspace.fs, exposes common filesystem operations including reading raw data from files and watching for changes.

The resolveCustomEditor6 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.readFile5 returns a promise that resolves to a Uint8Array containing the raw binary data. This Uint8Array can be passed to the SheetJS read method:

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
    // ...
  }
  // ...
}

Previewing Data

The resolveCustomEditor6 method of the CustomEditorProvider will be called when a file is opened. The second argument is a WebviewPanel7.

The webview.html nested property of the WebviewPanel controls the displayed HTML. Extensions can use SheetJS API methods.

The SheetJS sheet_to_html method generates a simple HTML table. The following snippet displays the data of the first worksheet:

export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
  // ...
  async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
    // ...
    // 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);
  }
  // ...
}

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.

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

Extensions must announce custom editor file type support in package.json. The selector property8 is expected to include "Glob Pattterns"9.

The demo uses the following package.json snippet to announce support for xls and xlsx spreadsheets:

  "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
      }
    ],
    // ...
  },

Usage Flow

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

:::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 sample file.

  2. Create a new VS Code extension

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 (use the default sheetjs-demo)
  • What's the description of your extension?: Press Enter (leave blank)
  • 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

  1. Install the SheetJS library and start the dev server:

{\ cd sheetjs-demo pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz pnpm run watch }

  1. Launch a new window with the VSCode fork and open the sheetjs-demo folder.

  2. Save the following codeblock to src/extension.ts:

import * as vscode from 'vscode';
import * as XLSX from 'xlsx';

class ExcelDocument implements vscode.CustomDocument {
  constructor(public readonly uri: vscode.Uri) { }
  dispose() { }
}

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);
  }

  // This is called whenever the user opens a new editor
  async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
    const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);

    const options: XLSX.ParsingOptions = { cellStyles: true, cellDates: true };
    const wb: XLSX.WorkBook = XLSX.read(data, options);

    const first_sheet = wb.Sheets[wb.SheetNames[0]];
    webviewPanel.webview.html = XLSX.utils.sheet_to_html(first_sheet);
  }
}

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);
}
export function deactivate() {}
  1. Add the highlighted lines to the contributes section of package.json:
  "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"
      }
    ]
  },
  1. In the editor, open the Command Palette (Help > "Show All Commands" from the menu), type Debug: Start and select Debug: Start Debugging.

This will compile and run the extension in a new Extension Development Host window.

  1. Drag and drop the pres.xlsx test file into the new window. If drag and drop is not available, click "Open..." in the Welcome screen and select the file.

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:

  "engines": {
    // highlight-next-line
    "vscode": "^1.100.0"
  }

:::


  1. See Webview API in the VSCode documentation for more details. ↩︎

  2. See Custom Editor API in the VSCode documentation for more details. ↩︎

  3. See vsce in the VSCode documentation for more details. ↩︎

  4. See CustomDocument in the VSCode API documentation for more details. ↩︎

  5. See FileSystemProvider in the VSCode API documentation for more details. ↩︎

  6. See CustomEditorProvider<T> in the VSCode API documentation for more details. ↩︎

  7. See WebviewPanel in the VSCode API documentation for more details. ↩︎

  8. See contributes.customEditors in the VSCode API documentation for more details. ↩︎

  9. See "Glob Patterns Reference" in the VSCode documentation for more details. ↩︎