Skip to content

When Clauses

When clauses are conditional expressions that control visibility and activation of commands and dock entries. The expression language matches VS Code's when-clause contexts, evaluated against a reactive context object.

The evaluator is whenexpr, which also provides the WhenExpression<Ctx, S> type helper used by defineCommand / defineDockEntry for compile-time validation — see Type-safe when clauses.

Usage

On commands

Controls whether the command appears in the palette and whether it can be triggered via shortcuts:

ts
ctx.commands.register(defineCommand({
  id: 'my-plugin:embedded-only',
  title: 'Embedded-Only Action',
  when: 'clientType == embedded',
  handler: async () => { /* ... */ },
}))

On dock entries

Controls whether a dock entry is visible in the dock bar:

ts
ctx.docks.register(defineDockEntry({
  id: 'my-plugin:inspector',
  title: 'Inspector',
  type: 'action',
  icon: 'ph:cursor-duotone',
  when: 'clientType == embedded',
  action: { importFrom: 'my-plugin/inspector' },
}))

when: 'false' hides a dock entry unconditionally.

Expression syntax

Operators

CategoryOperatorsExample
Bare truthyidentifierdockOpen
Literalstrue, false, numbers, stringstrue, 42, 'dev'
Unary!, -, +!paletteOpen
Logical&&, ||dockOpen && !paletteOpen
Equality==, !=, ===, !==clientType == embedded
Relational<, <=, >, >=count >= 10
Arithmetic+, -, *, /, %(a + b) * c
Grouping( … )(a || b) && c

Precedence (low to high)

||&& → equality → relational → + -* / % → unary → primary

== vs ===

  • == / != — VS Code when-clause idiom. Right-hand side is a single value token (bare identifier, quoted string, number, or boolean) and comparison is done as a string.
    ts
    evaluateWhen('clientType == embedded', ctx)
  • === / !== — JavaScript strict equality. Both sides are full expressions, no coercion.
    ts
    evaluateWhen('count === 1', { count: 1 }) // true
    evaluateWhen('count === 1', { count: '1' }) // false

Examples

ts
// Always visible
when: 'true'

// Never visible (unconditionally hidden)
when: 'false'

// Only in embedded mode
when: 'clientType == embedded'

// Only when dock is open and palette is closed
when: 'dockOpen && !paletteOpen'

// Compound with parentheses
when: '(clientType == embedded && dockOpen) || clientType == standalone'

// Plugin-specific context
when: 'vite.mode == development'

Built-in context variables

VariableTypeDescription
clientType'embedded' | 'standalone'Current client mode. embedded when running inside the host app overlay, standalone in a separate window.
dockOpenbooleanWhether the dock panel is currently open
paletteOpenbooleanWhether the command palette is currently open
dockSelectedIdstringID of the currently selected dock entry. Empty string '' (falsy) when no dock is selected.

Namespaced context keys

Plugins register context variables under namespaced keys (. or : separators) to avoid collisions. Use your plugin id as the prefix — my-plugin.featureEnabled, rolldown:buildStep.

ts
// Flat key (recommended)
context['vite.mode'] = 'development'
context['vite:buildMode'] = 'lib'

// Nested object (also supported)
context.vite = { mode: 'development', ssr: true }

Both styles can be used in when expressions:

ts
when: 'vite.mode == development'
when: 'vite:buildMode == lib'
when: 'vite.ssr'

Lookup order

When resolving a namespaced key like vite.mode:

  1. Exact matchctx['vite.mode'] is checked first.
  2. Nested pathctx.vite?.mode is the fallback.

Flat keys take priority over nested objects when both exist.

Type-safe when clauses

defineCommand and defineDockEntry capture the when: string as a TypeScript literal and validate it against WhenContext through whenexpr's WhenExpression<Ctx, S> helper. Syntax errors surface as compile-time errors at the call site.

ts
import { defineCommand } from '@vitejs/devtools-kit'

defineCommand({
  id: 'my-plugin:toggle',
  title: 'Toggle',
  when: 'dockOpen && !paletteOpen', // ✓ ok
  handler: async () => { /* ... */ },
})

defineCommand({
  id: 'my-plugin:broken',
  title: 'Broken',
  when: 'dockOpen &&& !paletteOpen',
  //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Type error: syntax error
  handler: async () => { /* ... */ },
})

Key validation with plugin-specific contexts

The default WhenContext uses [key: string]: unknown to keep namespaced plugin keys open-ended; that means built-in syntax validation alone won't catch typos like 'dockOpn == embedded'. For key-name validation in your plugin, define a narrower context shape and build a plugin-specific define* wrapper:

ts
import type { WhenContext, WhenExpression } from '@vitejs/devtools-kit'

interface MyPluginContext extends Omit<WhenContext, keyof any> {
  'clientType': 'embedded' | 'standalone'
  'dockOpen': boolean
  'paletteOpen': boolean
  'dockSelectedId': string
  'my-plugin.featureEnabled': boolean
}

function defineMyCommand<const W extends string>(cmd: {
  id: string
  title: string
  when?: WhenExpression<MyPluginContext, W>
  handler: (...args: any[]) => Promise<unknown>
}): typeof cmd {
  return cmd
}

defineMyCommand({
  id: 'my-plugin:toggle',
  title: 'Toggle',
  when: 'my-plugin.featureEnabled && dockOpen', // ✓ ok
  handler: async () => { /* ... */ },
})

defineMyCommand({
  id: 'my-plugin:broken',
  title: 'Broken',
  when: 'my-plugin.featureEnable', // ← typo
  //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Type error: Unknown context key
  handler: async () => { /* ... */ },
})

API reference

The when-clause evaluator is provided by devframe:

ts
import type { WhenContext } from '@vitejs/devtools-kit'
import { evaluateWhen, resolveContextValue } from 'devframe/utils/when'

const ctx: WhenContext = {
  'clientType': 'embedded',
  'dockOpen': true,
  'paletteOpen': false,
  'dockSelectedId': 'my-dock',
  'vite.mode': 'development',
}

evaluateWhen('dockOpen && vite.mode == development', ctx) // true
evaluateWhen('clientType == standalone', ctx) // false

resolveContextValue('vite.mode', ctx) // 'development'
resolveContextValue('dockOpen', ctx) // true

evaluateWhen(expression, ctx, options?)

Evaluates a when-clause expression string against a context object. Returns boolean. Pass { strict: true } to throw on unknown context keys — useful for catching typos during development.

resolveContextValue(key, ctx)

Resolves a single context key (including namespaced keys) from the context object. Returns unknown.

WhenContext

The context interface with built-in variables and an index signature for custom keys:

ts
interface WhenContext {
  clientType: 'embedded' | 'standalone'
  dockOpen: boolean
  paletteOpen: boolean
  dockSelectedId: string
  [key: string]: unknown // custom plugin variables
}

WhenExpression<Ctx, S>

Branded expression type re-exported from whenexpr. Use it to build your own typed define* helpers — see Key validation with plugin-specific contexts above.

Released under the MIT License.