Make your cursors dance with Kakoune and Helix-like modal editing in VS Code.
527
stars
489
commits
TypeScript
primary language
Mar 15, 2026
updated
Kakoune-inspired key bindings, modes, menus and scripting for Visual Studio Code.
Dance provides Kakoune-inspired commands and key bindings for Visual Studio Code, as well as support for custom modes and scripting.
Added key bindings are (mostly) compatible with Kakoune's, but are meant to be an addition to Visual Studio Code, rather than an emulation layer on top of it.
For most commands, the usage is the same as in Kakoune. However, the following changes have been made:
All modes are custom. By default, the normal and insert modes are defined,
and many Kakoune-inspired keybindings are available. More modes can be
created, though. These modes are configured with dance.modes.
For an example of this (which both creates a new mode and adds keybindings to it), see "Extend select mode" in the wiki.
Dance by default uses caret-based selections just like VS Code. This means a selection is anchored between two carets (i.e. positions between characters), and may be empty.
If you prefer character-based selections like Kakoune, please set
"selectionBehavior": "character" in the configuration of the mode in which you
wish to use character-based selections. This mode is designed to work with
block-style cursors, so your configuration would typically look like:
"dance.modes": {
"insert": {
// ...
},
"normal": {
"cursorStyle": "block",
"selectionBehavior": "character",
// ...
}
},
If this is enabled, Dance will internally treat selections as inclusive ranges between two characters and imply that each selection contains at least one character.
Most keybindings exposed by Dance are actually implemented by running several
Dance commands in a row. For instance, dance.modes.set.normal is actually a
wrapper around dance.modes.set with the argument { mode: "normal" }.
Commands that take an input, like dance.modes.set, will prompt a user for a
value if no argument is given.
Additionally to having commands with many settings, Dance also exposes the
dance.run command, which runs JavaScript code. That code has access to
the Dance API, and can perform operations with more control than Dance
commands. Where Dance commands in the dance.selections namespace operate the
same way on all selections at once, dance.run can be used to
individually manipulate selections. It can also be used to run several commands
at once.
Finally, the Dance API is exported by Dance. Other VS Code extensions can
specify that they depend on Dance (with the
extensionDependencies property),
and then access the API by calling
activate:
const { api } = await vscode.extensions.getExtension("gregoire.dance")
.activate();
Pipes no longer accept shell commands, but instead accept "expressions", those being:
#<shell command>: Pipes each selection into a shell command (the shell
respects the terminal.integrated.automationProfile.<os> profile).
/<pattern>[/<replacement>[/<flags>]: A RegExp literal, as
defined in JavaScript.
Do note the addition of a replacement, for commands that add or replace
text.
<JS expression>: A JavaScript expression in which the following variables
are available:
$: Text of the current selection.$$: Array of the text of all the selections.i: Index of the current selection.n: Number of selections in $$.Depending on the result of the expression, it will be inserted differently:
string: Inserted directly.number: Inserted in its string representation.boolean: Inserted as true or false.null: Inserted as null.undefined: Inserted as an empty string.object: Inserted as JSON./(\d+),(\d+)/$1.$2/g replaces 12,34 into 12.34.i + 1 replaces 1,1,1,1,1 into 1,2,3,4,5, assuming that each selection is
on a different digit.Dance provides several status bar segments (left-aligned) exposing info similar to Kakoune's default mode-line. Most of them are hidden by default and only shown contextually:
Dance also provides a custom view which lists all registers and their contents.
A few changes were made from Kakoune, mostly out of personal preference, and to make the extension integrate better with VS Code.
" maps to the system clipboard.RegExps
given to Dance commands support being given additional flags with the (?i)
syntax (but only at the start of the pattern).editor.lineNumbers configuration
value to on in insert mode, and relative in normal mode.type command. However, it sometimes needs access to the type
command, in dialogs and register selection, for instance. Consequently, it is
not compatible with extensions that always override the type command, such
as VSCodeVim; these extensions must therefore be disabled.swapescape is not respected), take a look at the
VS Code guide for
troubleshooting Linux keybindings.
TL;DR: adding "keyboard.dispatch": "keyCode" to your VS Code settings will
likely fix it.Dance also supports Helix keybindings, as they are
very similar to Kakoune's. The source code for all keybindings is shared in src,
with the Helix extension defining new modes (helix/normal,
...) with different sets of built-in keybindings.
The Helix extension is available in the VS Code marketplace.
See CONTRIBUTING.md.
TypeScript
99.2%
Make your cursors dance with Kakoune and Helix-like modal editing in VS Code.
527
stars
489
commits
TypeScript
primary language
Mar 15, 2026
updated
Kakoune-inspired key bindings, modes, menus and scripting for Visual Studio Code.
Dance provides Kakoune-inspired commands and key bindings for Visual Studio Code, as well as support for custom modes and scripting.
Added key bindings are (mostly) compatible with Kakoune's, but are meant to be an addition to Visual Studio Code, rather than an emulation layer on top of it.
For most commands, the usage is the same as in Kakoune. However, the following changes have been made:
All modes are custom. By default, the normal and insert modes are defined,
and many Kakoune-inspired keybindings are available. More modes can be
created, though. These modes are configured with dance.modes.
For an example of this (which both creates a new mode and adds keybindings to it), see "Extend select mode" in the wiki.
Dance by default uses caret-based selections just like VS Code. This means a selection is anchored between two carets (i.e. positions between characters), and may be empty.
If you prefer character-based selections like Kakoune, please set
"selectionBehavior": "character" in the configuration of the mode in which you
wish to use character-based selections. This mode is designed to work with
block-style cursors, so your configuration would typically look like:
"dance.modes": {
"insert": {
// ...
},
"normal": {
"cursorStyle": "block",
"selectionBehavior": "character",
// ...
}
},
If this is enabled, Dance will internally treat selections as inclusive ranges between two characters and imply that each selection contains at least one character.
Most keybindings exposed by Dance are actually implemented by running several
Dance commands in a row. For instance, dance.modes.set.normal is actually a
wrapper around dance.modes.set with the argument { mode: "normal" }.
Commands that take an input, like dance.modes.set, will prompt a user for a
value if no argument is given.
Additionally to having commands with many settings, Dance also exposes the
dance.run command, which runs JavaScript code. That code has access to
the Dance API, and can perform operations with more control than Dance
commands. Where Dance commands in the dance.selections namespace operate the
same way on all selections at once, dance.run can be used to
individually manipulate selections. It can also be used to run several commands
at once.
Finally, the Dance API is exported by Dance. Other VS Code extensions can
specify that they depend on Dance (with the
extensionDependencies property),
and then access the API by calling
activate:
const { api } = await vscode.extensions.getExtension("gregoire.dance")
.activate();
Pipes no longer accept shell commands, but instead accept "expressions", those being:
#<shell command>: Pipes each selection into a shell command (the shell
respects the terminal.integrated.automationProfile.<os> profile).
/<pattern>[/<replacement>[/<flags>]: A RegExp literal, as
defined in JavaScript.
Do note the addition of a replacement, for commands that add or replace
text.
<JS expression>: A JavaScript expression in which the following variables
are available:
$: Text of the current selection.$$: Array of the text of all the selections.i: Index of the current selection.n: Number of selections in $$.Depending on the result of the expression, it will be inserted differently:
string: Inserted directly.number: Inserted in its string representation.boolean: Inserted as true or false.null: Inserted as null.undefined: Inserted as an empty string.object: Inserted as JSON./(\d+),(\d+)/$1.$2/g replaces 12,34 into 12.34.i + 1 replaces 1,1,1,1,1 into 1,2,3,4,5, assuming that each selection is
on a different digit.Dance provides several status bar segments (left-aligned) exposing info similar to Kakoune's default mode-line. Most of them are hidden by default and only shown contextually:
Dance also provides a custom view which lists all registers and their contents.
A few changes were made from Kakoune, mostly out of personal preference, and to make the extension integrate better with VS Code.
" maps to the system clipboard.RegExps
given to Dance commands support being given additional flags with the (?i)
syntax (but only at the start of the pattern).editor.lineNumbers configuration
value to on in insert mode, and relative in normal mode.type command. However, it sometimes needs access to the type
command, in dialogs and register selection, for instance. Consequently, it is
not compatible with extensions that always override the type command, such
as VSCodeVim; these extensions must therefore be disabled.swapescape is not respected), take a look at the
VS Code guide for
troubleshooting Linux keybindings.
TL;DR: adding "keyboard.dispatch": "keyCode" to your VS Code settings will
likely fix it.Dance also supports Helix keybindings, as they are
very similar to Kakoune's. The source code for all keybindings is shared in src,
with the Helix extension defining new modes (helix/normal,
...) with different sets of built-in keybindings.
The Helix extension is available in the VS Code marketplace.
See CONTRIBUTING.md.
TypeScript
99.2%