Skip to main content

Contribution Points

Contribution points are the primary mechanism for extensions to extend the editor's user interface and behavior. Each contribution point represents a specific area of the application that extensions can plug into -- navigation drawers, status bars, file context menus, project templates, settings, and more.

Overview

Extensions declare contributions in their manifest.json under the contributes object. Each key in contributes maps to an array of contribution entries for that type. When the extension is loaded, the host parses these declarations and registers them with the editor.

Some contribution types (such as formatters and CodeMirror extensions) can also be registered at runtime via RPC calls, allowing extensions to add or remove contributions dynamically during their lifecycle.

Contribution types

The following contribution point types are supported:

TypeManifest keyDescription
commandcommandsCommands in the command palette
themethemesColor themes for the app and editor
settingsettingsExtension-specific settings
drawerIcondrawerIconsNavigation drawer sidebar items
statusBarItemstatusBarItemsStatus bar indicators and actions
toolsItemtoolsItemsHome screen tools menu items
projectTemplateprojectTemplatesProject creation templates
fileContextActionfileContextActionsFile/folder context menu actions
bottomSheetbottomSheetsBottom sheet panels with WebView content
codemirrorExtensioncodemirrorExtensionsCodeMirror 6 editor extensions
formatterformattersCode formatters for specific languages
customEditorcustomEditorsCustom file editors with webview UI

Priority system

Most UI-facing contribution types support a priority field that controls display ordering. Contributions are sorted in ascending order by priority -- lower values appear first.

FieldTypeDefaultDescription
priorityint100Sort order for display. Lower values appear first.

Contribution types that support priority: drawerIcons, toolsItems, projectTemplates, fileContextActions, statusBarItems.

If two contributions share the same priority, their relative order is determined by registration order (the order they appear in the manifest or the order they were added at runtime).

Example

{
"contributes": {
"drawerIcons": [
{ "id": "important-panel", "label": "Important", "icon": "star", "commandId": "myext.openImportant", "priority": 10 },
{ "id": "secondary-panel", "label": "Secondary", "icon": "info", "commandId": "myext.openSecondary", "priority": 200 }
]
}
}

The "Important" item appears before "Secondary" because 10 < 200.


Drawer icons

Manifest key: contributes.drawerIcons

Drawer icon contributions add items to the navigation drawer sidebar. Each entry can trigger a command, display HTML content in a panel, or open a URL.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this drawer icon.
labelStringYes--Display label shown in the drawer.
iconStringYes--Icon identifier (Material icon name or custom icon).
commandIdString?NonullCommand to execute when the icon is tapped.
htmlString?NonullHTML content to display in a panel when selected.
urlString?NonullURL to open when the icon is tapped.
priorityintNo100Sort order (ascending).

A drawer icon should specify at least one of commandId, html, or url to define what happens when the user taps it.

Manifest example

{
"contributes": {
"drawerIcons": [
{
"id": "docs-panel",
"label": "Documentation",
"icon": "menu_book",
"html": "<h1>Welcome</h1><p>Extension documentation goes here.</p>",
"priority": 50
},
{
"id": "settings-shortcut",
"label": "Extension Settings",
"icon": "settings",
"commandId": "myext.openSettings",
"priority": 150
},
{
"id": "website",
"label": "Visit Website",
"icon": "language",
"url": "https://example.com",
"priority": 200
}
]
}
}

Tools items

Manifest key: contributes.toolsItems

Tools item contributions add entries to the tools menu accessible from the home screen's tools button. Each item triggers a command when tapped.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this tools item.
labelStringYes--Display label shown in the tools menu.
iconStringYes--Icon identifier.
commandIdStringYes--Command to execute when the item is tapped.
priorityintNo100Sort order (ascending).

Manifest example

{
"contributes": {
"toolsItems": [
{
"id": "code-minifier",
"label": "Minify Code",
"icon": "compress",
"commandId": "myext.minifyCode",
"priority": 50
},
{
"id": "color-picker",
"label": "Color Picker",
"icon": "palette",
"commandId": "myext.colorPicker"
}
]
}
}

Project templates

Manifest key: contributes.projectTemplates

Project template contributions add entries to the project creation menu, accessible via the "+" button on the home screen. Each template triggers a command that handles the project scaffolding logic.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this template.
labelStringYes--Display label shown in the template list.
iconStringYes--Icon identifier.
commandIdStringYes--Command to execute when the template is selected.
priorityintNo100Sort order (ascending).

Manifest example

{
"contributes": {
"projectTemplates": [
{
"id": "react-app",
"label": "React App",
"icon": "web",
"commandId": "myext.createReactApp",
"priority": 10
},
{
"id": "node-api",
"label": "Node.js API",
"icon": "dns",
"commandId": "myext.createNodeApi",
"priority": 20
}
]
}
}

File context actions

Manifest key: contributes.fileContextActions

File context action contributions add entries to the three-dot context menu that appears on files and folders in the file tree. Actions can be scoped to specific file extensions or restricted to folders only.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this action.
labelStringYes--Display label shown in the context menu.
iconString?NonullOptional icon identifier.
commandIdStringYes--Command to execute when the action is selected.
fileExtensionsList<String>?NonullFile extensions this action applies to (e.g. [".js", ".ts"]). If null or empty, the action appears for all files.
appliesToFoldersboolNofalseWhether this action appears on folder context menus.
priorityintNo100Sort order (ascending).

File matching

If fileExtensions is null or empty, the action matches all files. Otherwise, the filename must end with at least one of the specified extensions.

When the context menu is built:

  • For files, actions are included if the filename matches the fileExtensions filter.
  • For folders, only actions with appliesToFolders: true are included.

Manifest example

{
"contributes": {
"fileContextActions": [
{
"id": "compile-ts",
"label": "Compile TypeScript",
"icon": "build",
"commandId": "myext.compileTs",
"fileExtensions": [".ts", ".tsx"],
"priority": 50
},
{
"id": "format-file",
"label": "Format File",
"commandId": "myext.formatFile"
},
{
"id": "run-tests-in-dir",
"label": "Run Tests in Folder",
"icon": "play_arrow",
"commandId": "myext.runTestsInDir",
"appliesToFolders": true,
"priority": 80
}
]
}
}

In this example:

  • "Compile TypeScript" only appears on .ts and .tsx files.
  • "Format File" appears on all files (no fileExtensions filter).
  • "Run Tests in Folder" only appears on folder context menus.

Status bar items

Manifest key: contributes.statusBarItems

Status bar item contributions add interactive indicators to the editor's status bar. Items can be aligned left or right and their labels can be updated dynamically at runtime.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this status bar item.
labelStringYes--Initial display text in the status bar.
iconString?NonullOptional icon shown alongside the label.
commandIdStringYes--Command to execute when the item is clicked.
alignmentStringNo"left"Horizontal alignment: "left" or "right".
priorityintNo100Sort order within the alignment group (ascending).

Dynamic label updates

Status bar items support dynamic label updates at runtime. Extensions can change the displayed text of any status bar item they own using the window.setStatusBarText RPC method:

await rpc.call("window.setStatusBarText", {
id: "my-status-item",
text: "Line 42, Col 10"
});

The updated text is displayed immediately in the UI. The override persists until the extension is deactivated, at which point the label reverts to the value declared in the manifest.

Manifest example

{
"contributes": {
"statusBarItems": [
{
"id": "git-branch",
"label": "main",
"icon": "commit",
"commandId": "myext.showBranches",
"alignment": "left",
"priority": 10
},
{
"id": "word-count",
"label": "Words: 0",
"commandId": "myext.showWordCountDetails",
"alignment": "right",
"priority": 50
}
]
}
}

Settings

Manifest key: contributes.settings

Setting contributions register extension-specific settings that appear in the app's settings UI alongside built-in settings. Each setting defines its type, default value, and metadata for the settings panel.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Identifier for this setting within the extension.
keyString?No"{extensionId}.{id}"Storage key. Auto-generated from the extension ID and setting ID if not specified.
labelString?NoValue of idDisplay label in the settings UI.
descriptionString?No""Description text shown below the label.
defaultValuedynamicNonullDefault value when the setting has not been configured. Alias: default.
typeStringNo"string"Data type: "string", "number", "boolean", or "enum".
enumValuesList<String>?NonullList of allowed values when type is "enum".

Key auto-generation

If the key field is not provided, it is automatically generated as {extensionId}.{id}. For example, an extension with ID "my-linter" and a setting with ID "severity" would produce the key "my-linter.severity". This ensures that setting keys are unique across extensions without requiring manual namespacing.

Supported type values

type valueDescription
"string"Free-form text input
"number"Numeric input
"boolean"Toggle switch (true/false)
"enum"Dropdown with values from enumValues

Any unrecognized type value defaults to "string".

Reading settings at runtime

Extensions can read their settings at runtime using the workspace.getConfiguration RPC method:

const config = await rpc.call("workspace.getConfiguration", {
section: "my-linter.severity"
});

Manifest example

{
"contributes": {
"settings": [
{
"id": "severity",
"label": "Lint Severity",
"description": "Minimum severity level for lint diagnostics",
"type": "enum",
"defaultValue": "warning",
"enumValues": ["error", "warning", "info", "hint"]
},
{
"id": "autoFix",
"label": "Auto-fix on Save",
"description": "Automatically apply safe fixes when a file is saved",
"type": "boolean",
"defaultValue": true
},
{
"id": "maxIssues",
"label": "Maximum Issues",
"description": "Maximum number of issues to report per file",
"type": "number",
"defaultValue": 100
},
{
"id": "configPath",
"key": "my-linter.customConfigPath",
"label": "Config File Path",
"description": "Path to a custom linter configuration file",
"type": "string",
"defaultValue": ""
}
]
}
}

In this example, the first three settings get auto-generated keys (my-linter.severity, my-linter.autoFix, my-linter.maxIssues), while the fourth setting uses an explicit key.


Commands

Manifest key: contributes.commands

Command contributions register commands that appear in the command palette and can be invoked programmatically. See Commands API for full details.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique command identifier (e.g. "myext.formatDocument").
labelString?NoLast segment of idDisplay label in the command palette.
descriptionString?No""Description shown alongside the label.
categoryString?No"Extensions"Category for grouping in the command palette.

Manifest example

{
"contributes": {
"commands": [
{
"id": "myext.formatDocument",
"label": "Format Document",
"description": "Format the current file using the configured formatter",
"category": "Editor"
},
{
"id": "myext.toggleFeature",
"label": "Toggle Feature X"
}
]
}
}

Themes

Manifest key: contributes.themes

Theme contributions define color themes for the application, editor, and syntax highlighting. See the dedicated Themes documentation for full details.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique theme identifier.
labelStringYes--Display name in the theme picker.
typeStringYes--Must be "dark" or "light".
appColorsMap<String, String>?NonullApp chrome color overrides.
editorColorsMap<String, String>?NonullCodeMirror editor color overrides.
tokenColorsMap<String, String>?NonullSyntax highlighting color overrides.

Formatters

Manifest key: contributes.formatters

Formatter contributions register code formatters for specific languages. Each formatter is backed by a command that receives the code to format and returns the formatted result. See the dedicated Formatters documentation for full details.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique formatter identifier.
labelStringYes--Display name for the formatter.
commandIdStringYes--Command that performs the formatting.
languagesList<String>No[]Language identifiers this formatter supports. If empty, the formatter matches all languages.

Formatters can also be registered and unregistered at runtime via the formatter.register and formatter.unregister RPC methods.

Language matching

If the languages list is empty, the formatter matches all languages. Otherwise, it matches only when the file's language identifier appears in the list.

Manifest example

{
"contributes": {
"formatters": [
{
"id": "prettier",
"label": "Prettier",
"commandId": "myext.formatWithPrettier",
"languages": ["javascript", "typescript", "css", "html", "json"]
}
]
}
}

CodeMirror extensions

Manifest key: contributes.codemirrorExtensions

CodeMirror extension contributions register custom CodeMirror 6 extensions that enhance the code editor. Extensions can be provided inline as JavaScript code or as bundled files. See CodeMirror Extensions for inline and file-based extension modes.

Note: CodeMirror extensions also apply to the diff editor. When a diff tab is opened, all registered CM extensions are loaded into the diff view automatically.

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this CodeMirror extension.
jsCodeStringNo*""JavaScript code that returns a CM6 Extension or Extension[] (inline mode).
descriptionString?NonullDescription of what this extension does.
fileExtensionsList<String>?NonullFile extensions this applies to. If null or empty, applies to all files.
fileString?NonullRelative path to a bundled JS file (file-based mode).
paramsMap<String, dynamic>?NonullParameters passed to the factory function (file-based mode).
*Either jsCode or file should be provided.

Registration modes

Inline mode: The jsCode field contains JavaScript that directly returns a CodeMirror Extension or Extension array. The code is evaluated in the editor's context.

File-based mode: The file field points to a bundled JavaScript file inside the extension's dist directory. The host reads the file content at bootstrap time. Optional params are forwarded to the factory function exported by the bundle.

File extension matching

If fileExtensions is null or empty, the CodeMirror extension applies to all files. Otherwise, it applies only to files matching one of the specified extensions.

CodeMirror extensions can also be registered at runtime via the editor.registerCodeMirrorExtension RPC method, which supports both inline and file-based modes.

Manifest example

{
"contributes": {
"codemirrorExtensions": [
{
"id": "vim-keybindings",
"description": "Vim-style keybindings for the editor",
"file": "dist/vim-extension.js"
},
{
"id": "line-highlight",
"description": "Highlight the current line",
"jsCode": "import { highlightActiveLine } from '@codemirror/view'; return highlightActiveLine();",
"fileExtensions": [".js", ".ts", ".dart"]
}
]
}
}

Bottom sheets

Manifest key: contributes.bottomSheets

Bottom sheet contributions define panels that slide up from the bottom of the screen, displaying WebView content (HTML or a URL).

Fields

FieldTypeRequiredDefaultDescription
idStringYes--Unique identifier for this bottom sheet.
titleStringYes--Title displayed at the top of the sheet.
urlString?NonullURL to load in the WebView.
htmlString?NonullHTML content to render in the WebView.
showTitleboolNotrueWhether to display the title bar.
showCloseButtonboolNotrueWhether to show a close button.
showOpenInTabboolNotrueWhether to show an "open in tab" button.

At least one of url or html should be provided.

Bottom sheets can also be shown at runtime via the window.showBottomSheet RPC method.

Manifest example

{
"contributes": {
"bottomSheets": [
{
"id": "preview-panel",
"title": "Live Preview",
"url": "https://localhost:3000",
"showOpenInTab": true
},
{
"id": "help-panel",
"title": "Quick Help",
"html": "<div style='padding:16px'><h2>Keyboard Shortcuts</h2><ul><li>Ctrl+S: Save</li><li>Ctrl+P: Command Palette</li></ul></div>",
"showCloseButton": true,
"showOpenInTab": false
}
]
}
}

Runtime contribution management

In addition to static manifest declarations, some contribution types can be managed dynamically at runtime via RPC methods:

  • Formatters -- use formatter.register and formatter.unregister to add or remove formatters at runtime.
  • CodeMirror extensions -- use editor.registerCodeMirrorExtension to add editor extensions at runtime.

When a contribution with the same type and ID already exists for the same extension, the existing entry is replaced. This allows extensions to update their contributions without reloading the manifest.

Deactivation cleanup

When an extension is deactivated, all of its contributions are automatically removed. Status bar label overrides are also cleaned up.


Complete manifest example

Below is a manifest.json demonstrating multiple contribution types in a single extension:

{
"id": "web-dev-toolkit",
"name": "Web Dev Toolkit",
"version": "2.0.0",
"description": "A comprehensive toolkit for web development",
"author": "Developer",
"main": "dist/index.js",
"activationEvents": ["*"],
"contributes": {
"commands": [
{
"id": "webdev.formatDocument",
"label": "Format Document",
"category": "Web Dev"
},
{
"id": "webdev.openPreview",
"label": "Open Live Preview",
"category": "Web Dev"
}
],
"settings": [
{
"id": "indentSize",
"label": "Indent Size",
"description": "Number of spaces per indentation level",
"type": "number",
"defaultValue": 2
},
{
"id": "formatOnSave",
"label": "Format on Save",
"description": "Automatically format files when saving",
"type": "boolean",
"defaultValue": false
}
],
"statusBarItems": [
{
"id": "webdev-server-status",
"label": "Server: Stopped",
"icon": "cloud_off",
"commandId": "webdev.toggleServer",
"alignment": "right",
"priority": 90
}
],
"drawerIcons": [
{
"id": "webdev-docs",
"label": "Web Dev Docs",
"icon": "menu_book",
"html": "<h1>Web Dev Toolkit</h1><p>Documentation for the Web Dev Toolkit extension.</p>",
"priority": 50
}
],
"toolsItems": [
{
"id": "webdev-minify",
"label": "Minify HTML/CSS/JS",
"icon": "compress",
"commandId": "webdev.minify"
}
],
"projectTemplates": [
{
"id": "webdev-vanilla",
"label": "Vanilla Web Project",
"icon": "web",
"commandId": "webdev.createVanillaProject",
"priority": 10
}
],
"fileContextActions": [
{
"id": "webdev-open-in-browser",
"label": "Open in Browser",
"icon": "open_in_browser",
"commandId": "webdev.openInBrowser",
"fileExtensions": [".html", ".htm"]
},
{
"id": "webdev-bundle-folder",
"label": "Bundle Folder",
"icon": "archive",
"commandId": "webdev.bundleFolder",
"appliesToFolders": true
}
],
"formatters": [
{
"id": "webdev-prettier",
"label": "Prettier (Web Dev)",
"commandId": "webdev.formatDocument",
"languages": ["javascript", "typescript", "css", "html"]
}
]
}
}