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:
| Type | Manifest key | Description |
|---|---|---|
command | commands | Commands in the command palette |
theme | themes | Color themes for the app and editor |
setting | settings | Extension-specific settings |
drawerIcon | drawerIcons | Navigation drawer sidebar items |
statusBarItem | statusBarItems | Status bar indicators and actions |
toolsItem | toolsItems | Home screen tools menu items |
projectTemplate | projectTemplates | Project creation templates |
fileContextAction | fileContextActions | File/folder context menu actions |
bottomSheet | bottomSheets | Bottom sheet panels with WebView content |
codemirrorExtension | codemirrorExtensions | CodeMirror 6 editor extensions |
formatter | formatters | Code formatters for specific languages |
customEditor | customEditors | Custom 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.
| Field | Type | Default | Description |
|---|---|---|---|
priority | int | 100 | Sort 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this drawer icon. |
label | String | Yes | -- | Display label shown in the drawer. |
icon | String | Yes | -- | Icon identifier (Material icon name or custom icon). |
commandId | String? | No | null | Command to execute when the icon is tapped. |
html | String? | No | null | HTML content to display in a panel when selected. |
url | String? | No | null | URL to open when the icon is tapped. |
priority | int | No | 100 | Sort 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this tools item. |
label | String | Yes | -- | Display label shown in the tools menu. |
icon | String | Yes | -- | Icon identifier. |
commandId | String | Yes | -- | Command to execute when the item is tapped. |
priority | int | No | 100 | Sort 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this template. |
label | String | Yes | -- | Display label shown in the template list. |
icon | String | Yes | -- | Icon identifier. |
commandId | String | Yes | -- | Command to execute when the template is selected. |
priority | int | No | 100 | Sort 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this action. |
label | String | Yes | -- | Display label shown in the context menu. |
icon | String? | No | null | Optional icon identifier. |
commandId | String | Yes | -- | Command to execute when the action is selected. |
fileExtensions | List<String>? | No | null | File extensions this action applies to (e.g. [".js", ".ts"]). If null or empty, the action appears for all files. |
appliesToFolders | bool | No | false | Whether this action appears on folder context menus. |
priority | int | No | 100 | Sort 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
fileExtensionsfilter. - For folders, only actions with
appliesToFolders: trueare 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
.tsand.tsxfiles. - "Format File" appears on all files (no
fileExtensionsfilter). - "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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this status bar item. |
label | String | Yes | -- | Initial display text in the status bar. |
icon | String? | No | null | Optional icon shown alongside the label. |
commandId | String | Yes | -- | Command to execute when the item is clicked. |
alignment | String | No | "left" | Horizontal alignment: "left" or "right". |
priority | int | No | 100 | Sort 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Identifier for this setting within the extension. |
key | String? | No | "{extensionId}.{id}" | Storage key. Auto-generated from the extension ID and setting ID if not specified. |
label | String? | No | Value of id | Display label in the settings UI. |
description | String? | No | "" | Description text shown below the label. |
defaultValue | dynamic | No | null | Default value when the setting has not been configured. Alias: default. |
type | String | No | "string" | Data type: "string", "number", "boolean", or "enum". |
enumValues | List<String>? | No | null | List 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 value | Description |
|---|---|
"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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique command identifier (e.g. "myext.formatDocument"). |
label | String? | No | Last segment of id | Display label in the command palette. |
description | String? | No | "" | Description shown alongside the label. |
category | String? | 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique theme identifier. |
label | String | Yes | -- | Display name in the theme picker. |
type | String | Yes | -- | Must be "dark" or "light". |
appColors | Map<String, String>? | No | null | App chrome color overrides. |
editorColors | Map<String, String>? | No | null | CodeMirror editor color overrides. |
tokenColors | Map<String, String>? | No | null | Syntax 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique formatter identifier. |
label | String | Yes | -- | Display name for the formatter. |
commandId | String | Yes | -- | Command that performs the formatting. |
languages | List<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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this CodeMirror extension. |
jsCode | String | No* | "" | JavaScript code that returns a CM6 Extension or Extension[] (inline mode). |
description | String? | No | null | Description of what this extension does. |
fileExtensions | List<String>? | No | null | File extensions this applies to. If null or empty, applies to all files. |
file | String? | No | null | Relative path to a bundled JS file (file-based mode). |
params | Map<String, dynamic>? | No | null | Parameters 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
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | String | Yes | -- | Unique identifier for this bottom sheet. |
title | String | Yes | -- | Title displayed at the top of the sheet. |
url | String? | No | null | URL to load in the WebView. |
html | String? | No | null | HTML content to render in the WebView. |
showTitle | bool | No | true | Whether to display the title bar. |
showCloseButton | bool | No | true | Whether to show a close button. |
showOpenInTab | bool | No | true | Whether 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.registerandformatter.unregisterto add or remove formatters at runtime. - CodeMirror extensions -- use
editor.registerCodeMirrorExtensionto 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"]
}
]
}
}